Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- voice version 1.1
- -- list of args
- local startupArgs = { ... }
- if #startupArgs < 1 or #startupArgs > 2 then
- print "Usage: voice <name> [mute]"
- return
- end
- -- whether we should mute turtle output
- local mute = "partial"
- if startupArgs[2] == "false" then
- mute = false
- elseif startupArgs[2] == "true" then
- mute = true
- end
- -- loading config data and defaults
- local config = {}
- if fs.exists( "voice.cfg" ) then
- local configFile = fs.open( "voice.cfg", "r" )
- config = textutils.unserialise( configFile.readAll() ) or {}
- configFile.close()
- end
- -- commands to disallow
- local blacklist = config.blacklist or {
- equipLeft = true, -- use "equip"
- equipRight = true, -- don't lose the chatbox, we need that
- wrap = true, -- useless
- find = true, -- useless
- }
- -- and programs
- local progBlacklist = config.progBlacklist or {
- -- will cause errors
- startup = true,
- voice = true,
- equip = true, -- use equip command
- -- locks the controller out
- edit = true,
- exit = true,
- lua = true,
- shell = true,
- shutdown = true,
- }
- local scriptPath = config.scriptPath or "scripts/"
- -- backward/forward compatibility
- local unpack = table.unpack or unpack
- -- only take input from a predetermined player
- local name = startupArgs[1]
- local label = os.getComputerLabel() or "Turtle"
- -- chat commands
- local chatbox = peripheral.wrap( "right" )
- local say, tell
- -- define data based on which chatbox we are using, or if we are using a modem
- local mode, eventType, opened
- local messages = {}
- local pType = peripheral.getType( "right" )
- if pType == "chatbox" then
- mode = "moar"
- eventType = "chatbox_command"
- chatbox.setLabel( label )
- function say( message )
- chatbox.say( message )
- sleep( 0.6 )
- end
- function tell( message )
- chatbox.tell( name, message )
- sleep( 0.6 )
- end
- elseif pType == "chatBox" then
- mode = "plus"
- eventType = "command"
- function say( message )
- chatbox.say( message, 60000000, true, label )
- sleep( 0.6 )
- end
- function tell( message )
- chatbox.tell( name, message, 60000000, true, label )
- sleep( 0.6 )
- end
- elseif pType == "modem" then
- name = tonumber( name )
- mode = "modem"
- eventType = "rednet_message"
- if not rednet.isOpen( "right" ) then
- opened = true
- rednet.open( "right" )
- end
- function tell( message )
- table.insert( messages, message )
- end
- else
- print "Unable to find chatbox"
- return
- end
- -- list of mute overrides, or commands that return even when muted
- -- basically any command that just returns a result
- local unmuted = config.unmuted or {
- --turtle
- compare = true,
- compareDown = true,
- compareUp = true,
- compareTo = true,
- detect = true,
- detectDown = true,
- detectUp = true,
- equip = true,
- getFuelLevel = true,
- getFuelLimit = true,
- getItemCount = true,
- getItemDetail = true,
- getItemSpace = true,
- getSelectedSlot = true,
- inspect = true,
- inspectDown = true,
- inspectUp = true,
- -- redstone
- getSides = true,
- getInput = true,
- getOutput = true,
- getAnalogInput = true,
- getAnalogOutput = true,
- getBndledInput = true,
- getBunledOutput = true,
- testBundledOutput = true,
- -- peripheral
- isPresent = true,
- getType = true,
- getMethods = true,
- getNames = true,
- -- MoarPeripherals
- getDensity = true, -- Density Scanning Turtle
- getNaturalLightLevel = true, -- Outdoorsy Turtle
- getFacing = true, -- Dizzy Turtle/Peripherals++ Navigational Turtle
- --chatbox
- getLabel = true,
- getReadRange = true,
- getMaxReadRange = true,
- getSayRange = true,
- getMaxSayRange = true,
- getTellRange = true,
- getMaxTellRange = true,
- -- Peripherals++
- getEntity = true, --Ridable Turtle
- getLiquid = true, --Thirsty Turtle
- getXP = true, --XP Turtle
- --Barrel Turtle
- getUnlocalizedName = true,
- getLocalizedName = true,
- getItemID = true,
- getAmount = true,
- getOreDictEntries = true,
- --Environment Scanner
- isRaining = true,
- getBiome = true,
- getTemperature = true,
- isSnow = true,
- --Equivalence Checking Turtle
- getEntries = true,
- doItemsMatch = true,
- --Gardening Turtle
- getGrowth = true,
- getGrowthUp = true,
- getGrowthDown = true,
- --Player Sensor
- getNearbyPlayers = true,
- getAllPlayers = true,
- --Sign Reading Turtle
- read = true,
- readUp = true,
- readDown = true,
- -- chat commands
- script = true,
- delete = true,
- program = true,
- -- error reporting
- Usage = true,
- ERROR = true
- }
- -- override print
- local consolePrint = print
- print = function( ... )
- if not mute then
- local strings = { ... }
- for _, v in ipairs( strings ) do
- tell( v )
- end
- end
- return consolePrint( ... )
- end
- -- print a bunch of messages
- function resultsPrint( com, results )
- local oldMute = mute
- if oldMute == "partial" and unmuted[com] then
- mute = false
- end
- if type( results ) == "table" then
- for i, v in ipairs( results ) do
- if v ~= nil then
- local comText = com .. ( #results == 1 and "" or " " .. i ) .. ": "
- if type( v ) == "table" then
- for k, w in pairs( v ) do
- print( comText .. k .. " = '" .. tostring(w) .. "'" )
- end
- else
- print( comText .. tostring(v) )
- end
- end
- end
- else
- print( com .. ": " .. tostring(results) )
- end
- mute = oldMute
- end
- -- write an error
- function resultsError( text )
- return resultsPrint( "ERROR", text )
- end
- -- split the input string into space separate parameters, for a few override functions
- function processArgs( input )
- local out = {}
- for match in string.gmatch( input, '%S+') do
- table.insert( out, match )
- end
- return out
- end
- -- process the input string into the command table
- -- format: { { { command, { arg, ... } }, ... }, number }
- function processCommand( input )
- local out = {}
- for match in string.gmatch( input, '%S+') do
- -- first, split out the number
- -- format - command:number
- local command, number
- if match:find( ":" ) then
- command = match:gsub( ":.*$", "" )
- number = tonumber(( match:gsub( "^.*:", "" ) ))
- else
- command = match
- number = 1
- end
- -- then, split apart our commands
- -- format - command+command2
- local commands = {}
- for match2 in command:gmatch( "([^+]+)" ) do
- table.insert( commands, match2 )
- end
- -- next, find the args
- -- format - command(arg,arg2)
- local results = {}
- for _, v in ipairs( commands ) do
- if v:find( "%(" ) then
- local command = v:gsub( "%(.*%)$", "" )
- local arg = v:gsub( "^.*%((.*)%)$", "%1" )
- local argList = {}
- for match in arg:gmatch( "([^,]+)" ) do
- -- numbers
- if tonumber( match ) then
- table.insert( argList, tonumber( match ) )
- -- boolean true
- elseif match == "true" then
- table.insert( argList, true )
- -- boolean false
- elseif match == "false" then
- table.insert( argList, false )
- -- string
- else
- -- character escapes for strings
- match = match
- :gsub( "%%%%", "%%X" ) -- %%: percent sign escape
- :gsub( "([^%%])%-", "%1 " ) -- -: space
- :gsub( "%%%-", "-" ) -- %-: underscore
- :gsub( "%%P", "+" ) -- %P: plus sign
- :gsub( "%%C", "," ) -- %C: comma
- :gsub( "%%L", "(" ) -- %L: left bracket
- :gsub( "%%R", ")" ) -- %R: right bracket
- :gsub( "%%N", ":" ) -- %N: colon
- :gsub( "%%T", "true" ) -- %T: standalone "true"
- :gsub( "%%F", "false" ) -- %F: standalone "false"
- :gsub( "%%X", "%%" ) -- %X: alternate percent sign escape
- table.insert( argList, match )
- end
- end
- table.insert( results, { command, argList } )
- else
- table.insert( results, { v, {} } )
- end
- end
- table.insert( out, { results, number } )
- end
- return out
- end
- -- peripheral commands
- local tool = peripheral.wrap( "left" )
- -- prevent function errors from crashing the program
- function callFunction( com, func, ... )
- local results = { pcall( func, ... ) }
- if results[1] then
- table.remove( results, 1 )
- resultsPrint( com, results )
- else
- resultsError( com .. ": " .. results[2]:gsub( "^pcall: ", "" ) )
- end
- end
- -- function to run commands, used for running scripts as well
- local runCommand -- recursion of sorts, this function can call itself
- local usedScripts = {} -- to prevent a script from running itself
- function runCommand( command )
- local commands = processCommand( command )
- for _, v in ipairs( commands ) do
- local num = v[2]
- if type( v[1] ) == "table" and type( num ) == "number" then
- for i = 1, v[2] do
- for _, comData in ipairs( v[1] ) do
- local com = comData[1]
- local args = comData[2]
- if blacklist[com] then
- resultsError( "Function '" .. com .. "' is blacklisted" )
- -- mute control
- elseif com == "mute" then
- if args[1] == true then
- mute = true
- elseif args[1] == false then
- mute = false
- else
- mute = "partial"
- end
- -- shorthand for mute(false)
- elseif com == "unmute" then
- mute = false
- -- turtle scripts, TODO: script writing command
- elseif com == "script" then
- if args[1] then
- local name = scriptPath .. args[1] .. ".tz"
- if fs.exists( name ) then
- if usedScripts[args[1]] then
- resultsError( "script: A script cannot run itself" )
- else
- usedScripts[args[1]] = true
- local file = fs.open( name, "r" )
- local script = file.readAll()
- file.close()
- -- don't allow using the script command in scripts, as a script should not eteranlly loop
- resultsPrint( "script", "Running script '" .. args[1] .. "'" )
- runCommand( script, true )
- usedScripts[args[1]] = nil
- end
- else
- resultsError( "script: Script does not exist" )
- end
- else
- resultsError( "script: Must specifiy a script" )
- end
- -- run a program from the turtle
- elseif com == "program" then
- if args[1] then
- if progBlacklist[args[1]] then
- resultsError( "program: Program is blacklisted" )
- else
- resultsPrint( "program", "Running program '" .. args[1] .. "'" )
- shell.run( table.concat( args, " " ) )
- end
- else
- resultsError( "program: Must specifiy a program" )
- end
- -- delay
- elseif com == "sleep" then
- if type( args[1] ) == "number" then
- resultsPrint( com, { sleep( args[1] ) } )
- else
- resultsError( "sleep: Number expected, got " .. type( args[1] ) )
- end
- -- swap tools and reload peripheral
- elseif com == "equip" then
- turtle.equipLeft()
- local pType = peripheral.getType( "left" ) or "tool/empty"
- resultsPrint( com, { pType } )
- tool = peripheral.wrap( "left" )
- -- and lastly chatbox commands
- elseif com == "say" and mode ~= "modem" then
- if args[1] then
- say( args[1] )
- end
- -- call a peripheral, either a turtle one or a block
- elseif peripheral[com] then
- callFunction( com, peripheral[com], unpack( args ) )
- -- if none of the others, first try a turtle command
- elseif turtle[com] then
- callFunction( com, turtle[com], unpack( args ) )
- -- then a redstone command
- elseif redstone[com] then
- callFunction( com, redstone[com], unpack( args ) )
- -- then a peripheral command
- elseif tool and tool[com] then
- callFunction( com, tool[com], unpack( args ) )
- else
- resultsError( "No such command '" .. com .. "'" )
- end
- end
- end
- else
- resultsError( "Broken command syntax" )
- end
- end
- end
- consolePrint( "Running 'voice' by KnightMiner" )
- consolePrint( "Press [end] to exit" )
- -- main loop
- while true do
- local event = { os.pullEvent() }
- if event[1] == "key" and event[2] == keys["end"] then
- break
- elseif event[1] == eventType then
- -- make sure we have the right protocol for a turtle
- local protocol = true
- if mode == "modem" then
- protocol = ( event[4] == "voice-command" )
- -- dump the side data when using a MoarPeripherals chatbox, Peripherals++ does not have that
- elseif mode == "moar" then
- table.remove( event, 2 )
- end
- -- only run on the predetermined player
- if event[2] == name and protocol then
- -- Peripherals++ separates commands by a space automatically, but does not trim the space near the \
- -- so just rejoin and manually split it later
- local command = event[3]
- if mode == "plus" then
- command = table.concat( command, ' ' ):gsub( '^\\ *', '' )
- end
- -- split the command into space separated stuff
- local args = processArgs( command )
- if args[1] == "script" then
- if args[2] then
- local name = scriptPath .. args[2] .. ".tz"
- if args[3] then
- if fs.exists( name ) then
- resultsError( "Script '" .. args[2] .. "' already exists" )
- else
- local file = fs.open( name, "w" )
- file.write( table.concat( args, "\n", 3 ) )
- file.close()
- resultsPrint( "script", "Saved script as '" .. args[2] .. "'" )
- end
- else
- if fs.exists( name ) then
- local file = fs.open( name, "r" )
- local script = file.readAll()
- file.close()
- resultsPrint( "script", script:gsub( "%s+", " " ) )
- else
- resultsError( "Script '" .. args[2] .. "' does not exist" )
- end
- end
- else
- resultsPrint( "Usage", "script <name> <command> ..." )
- end
- elseif args[1] == "delete" then
- if args[2] then
- local name = scriptPath .. args[2] .. ".tz"
- if fs.exists( name ) then
- fs.delete( name )
- resultsPrint( "delete", "Deleted script '" .. args[2] .. "'" )
- else
- resultsError( "Script '" .. args[2] .. "' does not exist" )
- end
- else
- resultsPrint( "Usage", "delete <name>" )
- end
- else
- runCommand( command )
- end
- -- send the messages to the control
- if mode == "modem" then
- sleep( 0.1 ) -- just in case it executes instantly
- rednet.send( name, messages, "voice-messages" )
- messages = {}
- end
- end
- end
- end
- -- shutdown tasks
- if opened then
- rednet.close( "right" )
- end
- print = consolePrint
Add Comment
Please, Sign In to add comment