Felkami

Slaughterbot Code

Feb 20th, 2013
1,043
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.66 KB | None | 0 0
  1. --[[
  2. Slaughterbot, by Felkami
  3. Free for use, do not remove my name.
  4.  
  5. Dependencies: Misc Peripherals Feeder, sword
  6.  
  7. Description: This program is designed to automatically breed ands slaughter livestock. It includes redstone trap activation, pausing on redstone signal, backup files so it can start where it leaves off after a reload, rudimentary inventory management, ability to use multiple inventory slots for feed, culling only the number of animals bred, minimum culling population to maintain population stability.
  8.    
  9. Instructions: The slaughterhouse for this program was built as an 11x11 pen of solid blocks leaving a 9x9 space inside. Fencing is not recommended as some animals can fit between the fencing and the water flow. Each corner of the 9x9 space has a water source block in it, so that there's 8 squares between each source block. Pistons block off each sourceblock and are set default ON via redstone inverters so that if the bot is not emitting redstone, the water is not flowing. When activated, the waterflow covers every square inside the 9x9 space except the center space. The slaughterbot goes in this center space.
  10.    
  11. Feel free to use other slaughterhouse designs if you have better ideas.
  12.    
  13. Feel free to manipulate the user configurable variables.
  14.    
  15. Feed has to go into slot 1, if that slot is empty, the bot will auto-exit after attempting to breed animals.
  16.    
  17. A redstone signal on any side except the side with the feeder on it (right side) will pause the slaughterbot program after it comes out of the sleep cycle. The misc. peripherals feeder does not transmit redstone for some reason.
  18. ]]--
  19.  
  20. --user configurable variables
  21. local growthtime = 20 --Time in minutes for animals to mature. Chickens and Cows are 20 minutes.
  22. local invleftstop = 6 --the total number of spaces left in inventory before the bot shuts down so as to not waste feed.
  23. local minpop = 4 --the minimum number of individually fed animals that the turtle will slaughter at.
  24. local savename = "slaughter.save" --the filename for the backup file incase the program stops uncleanly.
  25. local rstrapside = "bottom" --the side for the bot to emit redstone current from to activate the mob trap.
  26.  
  27.  
  28. --these are global variables for tracking statistics. Do not modify.
  29. local totalkills = 0 --tracks our total number of kills. Global because its referenced everywhere.
  30. local totalfeeds = 0 --tracks our total number of feeds. Global because its referenced everywhere.
  31.  
  32.  
  33. local function DrawBoard( text, ending ) --Draws the scoreboard. Return void
  34.  
  35.     local x, y = term.getCursorPos() --get the current curser position so we can go back to it later
  36.    
  37.     if y < 4 then --the top 3 lines are reserved for the drawboard, so move it out of that space after we draw the board.
  38.         x, y = 1, 4
  39.     end
  40.  
  41.     if text ~= nil then --if we're passed some text, print it.
  42.         term.setCursorPos(x,y) --change the curser position incase y < 4.
  43.         print( text )
  44.         x, y = term.getCursorPos()
  45.     end
  46.    
  47.     term.setCursorPos(1,1) --change to the top of the screen
  48.     term.clearLine()
  49.     print( "total feeds: " .. totalfeeds ) --reprint our stats board
  50.     term.clearLine()
  51.     print( "total kills: " .. totalkills )
  52.    
  53.     if not ending then --if the program is ending, we do some special stuff for pretty looks.
  54.         term.clearLine()
  55.         print( "Press Enter to end program" )
  56.     end
  57.    
  58.     term.setCursorPos(x, y) --return curser to previous position
  59.  
  60. end --end DrawBoard() function
  61.  
  62.  
  63. local function Escape() --Return void
  64.     while true do
  65.         local event, param = os.pullEvent( "key")
  66.         if param == keys.enter then
  67.             break
  68.         end
  69.     end -- end escape loop
  70. end --end escape function
  71.  
  72. local function Save( data, file ) --saves the data sent to it to the file given. Pass it a table. Return void
  73.     local f = fs.open( file, "w" )
  74.     f.write( textutils.serialize( data ) )
  75.     f.close()
  76. end --end Save function
  77.  
  78. local function Read( file ) --Reads the file given to it. Return table:contents
  79.     local f = fs.open( file, "r" )
  80.     local data = textutils.unserialize( f.readAll() )
  81.     f.close()
  82.     return data
  83. end --end Read function
  84.  
  85. local function RedstoneTest() --Return boolean:redstoneon?
  86.  
  87.     for sidenum, sidename in pairs(redstone.getSides()) do --get each side, then test it for current
  88.         if redstone.getInput( sidename ) then
  89.             return true
  90.         end
  91.     end
  92.  
  93.     return false
  94.    
  95. end --end RedstoneTest function
  96.  
  97. local function LongSleep() --Countdown while we wait for the animals to mature. Return void
  98.    
  99.     local x, y
  100.    
  101.     DrawBoard( growthtime .. " minutes until next cycle." )
  102.    
  103.     x, y = term.getCursorPos()
  104.    
  105.     for i = 1, growthtime do --count down every minute on the same line so we don't get scrolling numbers.
  106.         term.setCursorPos( 1, y - 1 ) --didn't use write for formatting issues on some exit scenarios.
  107.         term.clearLine()
  108.         print( growthtime + 1 - i .. " minutes until next cycle." )
  109.         sleep(60)
  110.     end --end for loop
  111.    
  112.     term.setCursorPos( 1, y - 1 )
  113.     term.clearLine()
  114.     print( "New cycle has begun.")
  115.  
  116. end --end function LongSleep()
  117.  
  118.  
  119. local function Attack( feedcount, killerror ) --Kill stuff! Raar! Return number:killerror
  120.  
  121.     local killcount = 0 --tracks our kills this time around.
  122.     local turncount = 0 --tracks how many times the bot's turned.
  123.    
  124.     feedcount =  math.floor( feedcount / 2 ) -- get the number of newly spawned animals
  125.  
  126.     if feedcount >= minpop then --kill only if we're at our stable population level
  127.         while killcount < feedcount do --kill only the number of newly bred animals
  128.        
  129.             if turtle.attack() then --attack until we get some failures
  130.                 killcount = killcount +1
  131.             elseif turtle.attackUp() then
  132.                 killcount = killcount + 1
  133.             else
  134.                 turtle.turnLeft() --turn left when nothing's been killed.
  135.                 turncount = turncount +1
  136.             end
  137.            
  138.             if turncount == 8 then --try each side twice, then admit failure.
  139.                 totalkills = totalkills + killcount
  140.                 DrawBoard("Error: Couldn't cull full quota.")
  141.                 return killerror + 1
  142.             end
  143.            
  144.         end --end while loop
  145.     else
  146.         DrawBoard( "Not enough animals fed to cull." )
  147.     end
  148.    
  149.     totalkills = totalkills + killcount
  150.    
  151.     return 0 --we successfully killed all the animals, yay!
  152.    
  153. end --end Attack() function
  154.  
  155.  
  156. local function Feed() --feed the animals. Return boolean:Halt(false = needfeed), number:feedcount
  157.  
  158.     local feedcount = 0
  159.  
  160.     for i = 1, 4 do --animals jump in water, so we'll repeat the feed loop to try and catch jumpers
  161.         sleep(1) --give them time to come back after jumping
  162.         while feeder.feed() do --feed until we cants feeds no more
  163.             feedcount = feedcount + 1
  164.         end --end feeder loop
  165.     end --end for loop
  166.    
  167.     if turtle.getItemCount(1) == 0 then --we don't continue without feed.
  168.         totalfeeds = totalfeeds + feedcount
  169.         DrawBoard("Critical Error: Out of feed.")
  170.         return false, feedcount
  171.     end
  172.    
  173.     totalfeeds = totalfeeds + feedcount
  174.     return true, feedcount
  175.    
  176. end --end Feed() function
  177.  
  178.  
  179. local function Inventory() --Inventory management. Return Boolean:Halt(false = need inventory space)
  180.  
  181.     local invtotal = 0 --for storing our total item space in inventory
  182.  
  183.     if turtle.getItemSpace(1) ~= 0 then --make sure we're good on feedstock
  184.         for i = 2, 16 do --fill up slot 1, our feed slot
  185.             turtle.select( i )
  186.             if turtle.compareTo( 1 ) then
  187.                 turtle.transferTo( 1, turtle.getItemSpace( 1 ) )
  188.             end
  189.         end -- end for loop
  190.         turtle.select( 1 ) --go back to our feed slot
  191.     end
  192.  
  193.     for i = 2, 16 do --total available inventory space, start with 2 because 1 is our feedslot
  194.        
  195.             invtotal = invtotal + turtle.getItemSpace( i )
  196.            
  197.     end --end for loop
  198.  
  199.     if invtotal <= invleftstop then --if inventory is full, critical throw error
  200.         DrawBoard("Critical Error: Inventory full.")
  201.         return false
  202.     end
  203.    
  204.     return true
  205.    
  206. end --end Inventory() function
  207.  
  208. local function Suck() --collecting any items around turtle. Return void
  209.  
  210.     for i = 1 ,4 do
  211.         turtle.suck()
  212.         turtle.turnRight()
  213.     end --end for loop
  214.     turtle.suckUp()
  215.    
  216. end --end Suck() function
  217.  
  218.  
  219. local function Main()
  220.  
  221.     local feedcount = 0 --tracks the number of feeds per cycle
  222.    
  223.     local killerror = 0 --tracks our total number of kill errors
  224.     local feederror = 0 --tracks our total number of feed errors
  225.    
  226.     local continue = true --maintains our main loop
  227.    
  228.     --The startup sequence
  229.    
  230.     feeder = peripheral.wrap( "right" ) --we need a feeder!
  231.     turtle.select(1) --select feedslot on initial start
  232.     minpop = minpop/2 --halve minpop for comparison to feedcount (2 animals = 1 spawnling)
  233.     term.clear() --clear the screen on initial start
  234.     term.setCursorPos(1,1)
  235.    
  236.    
  237.     if fs.exists( shell.dir() .. "/" .. savename ) then --check for a backup file, if it exists, read it and restore the variables.
  238.         local data = Read( shell.dir() .. "/" .. savename )
  239.         totalkills = data.totalkills
  240.         totalfeeds = data.totalfeeds
  241.         feedcount = data.feedcount
  242.         killerror = data.killerror
  243.         feederror = data.feederror
  244.         continue = data.continue
  245.         DrawBoard( "Save data found, restoring from backup." )
  246.     end
  247.    
  248.     DrawBoard( "Starting Program in 10 seconds." ) --setup our scoreboard
  249.    
  250.     sleep(10) --scurry! scurry! scurry!
  251.     term.clearLine()
  252.     DrawBoard("Program started") --incase rushing water wasn't obvious enough.
  253.    
  254.     if fs.exists( shell.dir() .. "/" .. savename ) then --if we restored from backup, sleep for growthtime to let animals mature.
  255.         LongSleep()
  256.     end
  257.        
  258.    
  259.     --The meat of the program
  260.    
  261.     while continue do --main loop
  262.    
  263.         if RedstoneTest() then --Pause cycle if redstone current detected.
  264.             DrawBoard( "Redstone detected, Pausing." )
  265.             while RedstoneTest() do
  266.                 sleep(10)
  267.             end --end while loop
  268.             DrawBoard( "Redstone off, continuing." )
  269.         end
  270.        
  271.         redstone.setOutput( rstrapside, true) --bring animals to turtle
  272.        
  273.         sleep( 30 ) --wait half a minute, some animals are stubborn
  274.        
  275.         killerror = Attack( feedcount, killerror ) --Kill things!
  276.        
  277.         sleep(1) --I'm so kind, I'm giving the animals a rest after the mass slaughter!
  278.        
  279.         continue, feedcount = Feed() --Feedses thems!
  280.        
  281.         Suck() --gather any extra items sitting around the turtle
  282.        
  283.         redstone.setOutput( rstrapside, false) --let my people go.
  284.        
  285.         if continue then --we check this so that if Feed() passed a false, Inventory() doesn't overwrite it.
  286.             continue = Inventory()
  287.         else
  288.             Inventory()
  289.         end
  290.        
  291.         --Error Handling
  292.            
  293.         if feedcount < 2 then --If we fed less than 4 animals, then we might have a population collapse
  294.             feederror = feederror + 1
  295.             print("Error: Not enough animals bred.")
  296.         else
  297.             feederror = 0
  298.         end
  299.        
  300.         if feederror >= 3 then --if we get 3 feederrors in a row, we'll terminate the program
  301.             continue = false
  302.             print("Critical Error: 3 feed fails in a row.")
  303.         end
  304.        
  305.         if killerror >= 3 then --if we get 3 killerrors in a row, we'll terminate the program
  306.             continue = false
  307.             print("Critical Error: 3 cull fails in a row.")
  308.         end
  309.        
  310.         DrawBoard()
  311.        
  312.         if not continue then --if anything threw a Halt, then we break the loop
  313.             break
  314.         end
  315.        
  316.         --backup the variables to savename incase we shutdown during the long sleep.
  317.         Save( { totalkills = totalkills, totalfeeds = totalfeeds, feedcount = feedcount, killerror = killerror, feederror = feederror, continue = continue }, shell.dir() .. "/" .. savename )
  318.        
  319.         --Now the long sleep
  320.        
  321.         LongSleep() --wait for animals to mature
  322.        
  323.     end --end main loop
  324.    
  325. end --end Main() function
  326.  
  327.  
  328. parallel.waitForAny( Main, Escape ) --starts our program
  329.  
  330. if fs.exists( shell.dir() .. "/" .. savename ) then --prompt to delete the backup file.
  331.     DrawBoard( "Delete Backup (y/n)?" )
  332.     local event, param = os.pullEvent( "key" )
  333.     if param == 21 then
  334.         fs.delete( shell.dir() .. "/" .. savename ) --delete the backup.
  335.         DrawBoard( "Backup file deleted!" )
  336.     end
  337. end
  338.  
  339.  
  340. redstone.setOutput( rstrapside, false) --stop water if its running
  341. DrawBoard("Ending program", true) --important information!
Advertisement
Add Comment
Please, Sign In to add comment