Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Slaughterbot, by Felkami
- Free for use, do not remove my name.
- Dependencies: Misc Peripherals Feeder, sword
- 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.
- 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.
- Feel free to use other slaughterhouse designs if you have better ideas.
- Feel free to manipulate the user configurable variables.
- Feed has to go into slot 1, if that slot is empty, the bot will auto-exit after attempting to breed animals.
- 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.
- ]]--
- --user configurable variables
- local growthtime = 20 --Time in minutes for animals to mature. Chickens and Cows are 20 minutes.
- local invleftstop = 6 --the total number of spaces left in inventory before the bot shuts down so as to not waste feed.
- local minpop = 4 --the minimum number of individually fed animals that the turtle will slaughter at.
- local savename = "slaughter.save" --the filename for the backup file incase the program stops uncleanly.
- local rstrapside = "bottom" --the side for the bot to emit redstone current from to activate the mob trap.
- --these are global variables for tracking statistics. Do not modify.
- local totalkills = 0 --tracks our total number of kills. Global because its referenced everywhere.
- local totalfeeds = 0 --tracks our total number of feeds. Global because its referenced everywhere.
- local function DrawBoard( text, ending ) --Draws the scoreboard. Return void
- local x, y = term.getCursorPos() --get the current curser position so we can go back to it later
- 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.
- x, y = 1, 4
- end
- if text ~= nil then --if we're passed some text, print it.
- term.setCursorPos(x,y) --change the curser position incase y < 4.
- print( text )
- x, y = term.getCursorPos()
- end
- term.setCursorPos(1,1) --change to the top of the screen
- term.clearLine()
- print( "total feeds: " .. totalfeeds ) --reprint our stats board
- term.clearLine()
- print( "total kills: " .. totalkills )
- if not ending then --if the program is ending, we do some special stuff for pretty looks.
- term.clearLine()
- print( "Press Enter to end program" )
- end
- term.setCursorPos(x, y) --return curser to previous position
- end --end DrawBoard() function
- local function Escape() --Return void
- while true do
- local event, param = os.pullEvent( "key")
- if param == keys.enter then
- break
- end
- end -- end escape loop
- end --end escape function
- local function Save( data, file ) --saves the data sent to it to the file given. Pass it a table. Return void
- local f = fs.open( file, "w" )
- f.write( textutils.serialize( data ) )
- f.close()
- end --end Save function
- local function Read( file ) --Reads the file given to it. Return table:contents
- local f = fs.open( file, "r" )
- local data = textutils.unserialize( f.readAll() )
- f.close()
- return data
- end --end Read function
- local function RedstoneTest() --Return boolean:redstoneon?
- for sidenum, sidename in pairs(redstone.getSides()) do --get each side, then test it for current
- if redstone.getInput( sidename ) then
- return true
- end
- end
- return false
- end --end RedstoneTest function
- local function LongSleep() --Countdown while we wait for the animals to mature. Return void
- local x, y
- DrawBoard( growthtime .. " minutes until next cycle." )
- x, y = term.getCursorPos()
- for i = 1, growthtime do --count down every minute on the same line so we don't get scrolling numbers.
- term.setCursorPos( 1, y - 1 ) --didn't use write for formatting issues on some exit scenarios.
- term.clearLine()
- print( growthtime + 1 - i .. " minutes until next cycle." )
- sleep(60)
- end --end for loop
- term.setCursorPos( 1, y - 1 )
- term.clearLine()
- print( "New cycle has begun.")
- end --end function LongSleep()
- local function Attack( feedcount, killerror ) --Kill stuff! Raar! Return number:killerror
- local killcount = 0 --tracks our kills this time around.
- local turncount = 0 --tracks how many times the bot's turned.
- feedcount = math.floor( feedcount / 2 ) -- get the number of newly spawned animals
- if feedcount >= minpop then --kill only if we're at our stable population level
- while killcount < feedcount do --kill only the number of newly bred animals
- if turtle.attack() then --attack until we get some failures
- killcount = killcount +1
- elseif turtle.attackUp() then
- killcount = killcount + 1
- else
- turtle.turnLeft() --turn left when nothing's been killed.
- turncount = turncount +1
- end
- if turncount == 8 then --try each side twice, then admit failure.
- totalkills = totalkills + killcount
- DrawBoard("Error: Couldn't cull full quota.")
- return killerror + 1
- end
- end --end while loop
- else
- DrawBoard( "Not enough animals fed to cull." )
- end
- totalkills = totalkills + killcount
- return 0 --we successfully killed all the animals, yay!
- end --end Attack() function
- local function Feed() --feed the animals. Return boolean:Halt(false = needfeed), number:feedcount
- local feedcount = 0
- for i = 1, 4 do --animals jump in water, so we'll repeat the feed loop to try and catch jumpers
- sleep(1) --give them time to come back after jumping
- while feeder.feed() do --feed until we cants feeds no more
- feedcount = feedcount + 1
- end --end feeder loop
- end --end for loop
- if turtle.getItemCount(1) == 0 then --we don't continue without feed.
- totalfeeds = totalfeeds + feedcount
- DrawBoard("Critical Error: Out of feed.")
- return false, feedcount
- end
- totalfeeds = totalfeeds + feedcount
- return true, feedcount
- end --end Feed() function
- local function Inventory() --Inventory management. Return Boolean:Halt(false = need inventory space)
- local invtotal = 0 --for storing our total item space in inventory
- if turtle.getItemSpace(1) ~= 0 then --make sure we're good on feedstock
- for i = 2, 16 do --fill up slot 1, our feed slot
- turtle.select( i )
- if turtle.compareTo( 1 ) then
- turtle.transferTo( 1, turtle.getItemSpace( 1 ) )
- end
- end -- end for loop
- turtle.select( 1 ) --go back to our feed slot
- end
- for i = 2, 16 do --total available inventory space, start with 2 because 1 is our feedslot
- invtotal = invtotal + turtle.getItemSpace( i )
- end --end for loop
- if invtotal <= invleftstop then --if inventory is full, critical throw error
- DrawBoard("Critical Error: Inventory full.")
- return false
- end
- return true
- end --end Inventory() function
- local function Suck() --collecting any items around turtle. Return void
- for i = 1 ,4 do
- turtle.suck()
- turtle.turnRight()
- end --end for loop
- turtle.suckUp()
- end --end Suck() function
- local function Main()
- local feedcount = 0 --tracks the number of feeds per cycle
- local killerror = 0 --tracks our total number of kill errors
- local feederror = 0 --tracks our total number of feed errors
- local continue = true --maintains our main loop
- --The startup sequence
- feeder = peripheral.wrap( "right" ) --we need a feeder!
- turtle.select(1) --select feedslot on initial start
- minpop = minpop/2 --halve minpop for comparison to feedcount (2 animals = 1 spawnling)
- term.clear() --clear the screen on initial start
- term.setCursorPos(1,1)
- if fs.exists( shell.dir() .. "/" .. savename ) then --check for a backup file, if it exists, read it and restore the variables.
- local data = Read( shell.dir() .. "/" .. savename )
- totalkills = data.totalkills
- totalfeeds = data.totalfeeds
- feedcount = data.feedcount
- killerror = data.killerror
- feederror = data.feederror
- continue = data.continue
- DrawBoard( "Save data found, restoring from backup." )
- end
- DrawBoard( "Starting Program in 10 seconds." ) --setup our scoreboard
- sleep(10) --scurry! scurry! scurry!
- term.clearLine()
- DrawBoard("Program started") --incase rushing water wasn't obvious enough.
- if fs.exists( shell.dir() .. "/" .. savename ) then --if we restored from backup, sleep for growthtime to let animals mature.
- LongSleep()
- end
- --The meat of the program
- while continue do --main loop
- if RedstoneTest() then --Pause cycle if redstone current detected.
- DrawBoard( "Redstone detected, Pausing." )
- while RedstoneTest() do
- sleep(10)
- end --end while loop
- DrawBoard( "Redstone off, continuing." )
- end
- redstone.setOutput( rstrapside, true) --bring animals to turtle
- sleep( 30 ) --wait half a minute, some animals are stubborn
- killerror = Attack( feedcount, killerror ) --Kill things!
- sleep(1) --I'm so kind, I'm giving the animals a rest after the mass slaughter!
- continue, feedcount = Feed() --Feedses thems!
- Suck() --gather any extra items sitting around the turtle
- redstone.setOutput( rstrapside, false) --let my people go.
- if continue then --we check this so that if Feed() passed a false, Inventory() doesn't overwrite it.
- continue = Inventory()
- else
- Inventory()
- end
- --Error Handling
- if feedcount < 2 then --If we fed less than 4 animals, then we might have a population collapse
- feederror = feederror + 1
- print("Error: Not enough animals bred.")
- else
- feederror = 0
- end
- if feederror >= 3 then --if we get 3 feederrors in a row, we'll terminate the program
- continue = false
- print("Critical Error: 3 feed fails in a row.")
- end
- if killerror >= 3 then --if we get 3 killerrors in a row, we'll terminate the program
- continue = false
- print("Critical Error: 3 cull fails in a row.")
- end
- DrawBoard()
- if not continue then --if anything threw a Halt, then we break the loop
- break
- end
- --backup the variables to savename incase we shutdown during the long sleep.
- Save( { totalkills = totalkills, totalfeeds = totalfeeds, feedcount = feedcount, killerror = killerror, feederror = feederror, continue = continue }, shell.dir() .. "/" .. savename )
- --Now the long sleep
- LongSleep() --wait for animals to mature
- end --end main loop
- end --end Main() function
- parallel.waitForAny( Main, Escape ) --starts our program
- if fs.exists( shell.dir() .. "/" .. savename ) then --prompt to delete the backup file.
- DrawBoard( "Delete Backup (y/n)?" )
- local event, param = os.pullEvent( "key" )
- if param == 21 then
- fs.delete( shell.dir() .. "/" .. savename ) --delete the backup.
- DrawBoard( "Backup file deleted!" )
- end
- end
- redstone.setOutput( rstrapside, false) --stop water if its running
- DrawBoard("Ending program", true) --important information!
Advertisement
Add Comment
Please, Sign In to add comment