Probably the best part of the program is the function based on the very flexible and useful replacement for go utility (which I refer to as "gox") by tele_iz_dva4a. This function accepts a string of commands encompassing most of the available turtle functions and allows loops and enumerated iterations, so it can do most of the things that novice users spend time programing to get some basic utility out of their turtles.
I've also included a function based on the nifty Satellite Builder by dustpuppy. Though this is a somewhat more specialized function, which just launches a four-node GPS array to the top of the map, it can be a real time saver for a new world (it also illustrates some of the principles of turtle/computer interaction that are of interest to those who want to eventually have an automated machine nation). It can be used to place multiple arrays and makes an effort to keep them consistent with each other (though success is spotty, sometimes the automatic GPS finding works and sometimes it doesn't). The function only overrides the user provided coordinates if it finds a valid GPS system in place, so if it doesn't work then nothing bad happens.
I also included a couple of functions that I find useful, such as a simple bone-meal based wheat farmer (to use up all the bones you aren't feeding to dogs), a gravel sifter (in case you want to turn a hundreds of blocks of gravel into flint rather than using it to make paths that collapse when their underlayment gets removed), and a basic remote control function.
I now have a user guide for clfn in the spoiler below.
Spoiler
Okay, a complete user guide to the remote functions of clfn. These are the rednet messages that you can send to the clfn turtle when it is in remote controlled mode.Any turtle API function, without the "turtle." and without (). Where a parameter is used, the default will be 1, otherwise you can specify it with a number. Thus turtle.forward() is "forward", and turtle.select(8) is "select 8". The clfn turtle will respond with a message that contains the value of the return.
Any of the functions described below:
"dfd", "dup", "ddn" move forward, up, or down (digging and attacking to remove obsticles). If the turtle cannot move then it outputs the reason it couldn't move and returns false.
"tnl" digUp, digDown, then dfd as described above.
"bmb" placeDown a block from the selected slot, then output redstone power to it. If the block is successfully placed and then becomes an entity or item, bmb returns true, otherwise false (note that this returns true for sand and gravel as well as tnt, and for some items that are successfully used with placeDown, but it returns false for buckets of water and lava).
"pckup" executes the suck commands. Needs revision to be more useful (I assumed it did more than it does cause I named it too clearly).
"chst" place a block from slot 16 and drops everthing else into it. Returns false if the block couldn't be placed, otherwise returns true. Do not use this command if slot 16 doesn't contain a placeable block with an inventory sufficient to hold the dump.
"slct" increments the selection value (rolling around if it is 16) and selects that slot. Returns a string specifying the newly selected slot and the stack size over the stack limit
"rfl" Outputs the current fuel level, attempts to use the currently selected slot as fuel, and returns a string containing the new fuel level if successful or false if the selected slot does not contain fuel
"gpslct" returns a string containing the GPS coordinates, or nil if it cannot get a GPS fix.
"gpshst" allows the turtle to act as a temporary GPS host to help extend the range of an existing GPS system. The turtle replies with the message "Serving GPS from x,y,z" (where x,y,z are it's GPS coordinates). When it receives "PING", it responds to the sender as a GPS host but also outputs the ID of the PING sender and the distance from which it was PINGed. If the turtle is out of range of a consistent system or receives the "gpshst" command a second time, it returns "GPS hosting terminated".
The following commands require additional parameters and explaination.
"gox "..command_string executes a series of commands, in iterations and loops, specified by command_string. The commands are single characters, mapped to commands by the following key:
f,b,u,d, are the movement commands, moving the turtle forward, back, up, or down. b is the normal turtle back command, while f,u,and d use the "dfd","dup", and "ddn" commands described above and will attempt to dig/attack obsticles.
t, uses the "tnl" command above, digging up and down as it moves.
l,r, are to turn left and right.
p,P,o, are the place, placeUp, and placeDown commands
x,X,z, are the drop, dropUp, and dropDown commands
e,E,w, are the dig, digUp, and digDown commands
v,V,c, are the suck, suckUp, and suckDown commands
R,S,B,C, use the "rfl","slct","bmb", and "chst" commands as described above.
Following a command by a number will cause the command to be repeated that many times.
Enclosing a sequence of commands in square brackets (i.e. []) will cause those commands to be executed in a loop that will end when the last command in the loop returns false or nil, unless the closing bracket is followed by a number, in which case the loop will end after that many iterations. Non-iterated loops (not following the closing "]" with a number) should only be used with caution. A command string like "gox [t]" probably won't stop till it hits bedrock or an unloaded chunk, or the turtle runs out of fuel.
You can put loops inside of loops, and thus build up fairly complex actions. "gox [[Pobp]5l]4" will build a nice little 6 meter square enclosure (the final bp doesn't happen, though). "gox [[Pobp]5l]4bpS[[ob]4lbl[ob]4rbr]2" will complete the wall, switch the selected slot, and put down a nice floor. You can extend this to "gox [[[[Pobp]5l]4bpS[[ob]4lbl[ob]4rbr]2u3frfS]8" to reposition the turtle on top of the corner of the wall and repeat the wall/floor building 8 times (at which point you will be pretty much all out of building materials). More simply, you can encode an excavate type program, with use of C to dump off materials when you are likely to be getting full. (edited to make the brackets match up, match your brackets or brick your turtle, also, test your command strings in sections before assembling anything this complex).
The "gox" command shouldn't be underestimated as to it's usefulness or as to the dangers of using it carelessly, it's as easy to program it to destroy as create (a bit easier, really). And a missed turn or movement can make an entire command sequence behave quite strangely.
"rcvfl "..filename.." "..filebodytext allows the turtle to receive a text file over rednet. The rcvfl function takes the first "word" of non space characters to be the name of the file to be created/overwritten, and everything after that to be the text of the file. The file contents will not begin with a space but can contain spaces (the function can be modified to allow a space at the beginning of the file but currently this is not desired). When the file is written the function returns filename.." updated". The main intended purpose is to allow writing short control files like startup or very simple programs that are going to be used later, but it can also be used as the receiving half of a file transfer protocal.
"srvfl "..filename allows the turtle to serve a specified file over rednet. The file is served as a rednet message (and mirrored on the turtle's console), and the function returns filename.." served". The main intended purpose is to allow viewing short control files like startup or very simple programs that are going to be used later, but it can also be used as the serving half of a file transfer protocal (but not corresponding directly to rcvfl).
"xqtfl "..filename allows the turtle to execute a program file. After the file has run, the startup file on the turtle is rewritten to run clfn in remote control mode with the current controllerID. Certain command line parameters (those with entirely alphanumberic form) can be passed, separated by spaces from each other and the program filename.
"ldstrng "..luacodestring allows the turtle to execute a supplied lua code string. It is intended for expert use only, and returns the function if the provided string is successfully interpreted as one or the error message generated if the string was not valid lua code. Note, code that is syntactically valid but throws errors will terminate clfn, resulting in losing remote control of the turtle.
That's pretty much the laundry list of what clfn can do by remote control and using gox command strings. The other clfn actions should be easier to use, but if there are questions about them then feel free to ask.
The rcpda and rctrl functions are intended to be used with clfn remote control mode and make sending most of the available commands pretty simple. See their program descriptions for more details.
The program can be considered more of a starting point, if you want to build on it. The code is in the following spoiler, check the bottom of this post for the pastebin links.
Spoiler
local tArgs = { ... }
local cldt = {}
local tfnctns = {}
local mvfncs = {{turtle.forward,turtle.detect,turtle.dig,turtle.attack},
{turtle.up,turtle.detectUp,turtle.digUp,turtle.attackUp},
{turtle.down,turtle.detectDown,turtle.digDown,turtle.attackDown},}
local function trply(mssgstr) -- e.g. "unbreakable block in path"
print(mssgstr)
if cldt.rcID then rednet.send(cldt.rcID,mssgstr) end
end
local function mvdgK(drctn) -- i.e.(1 = forward, 2 = up, 3 = down)
local itr8 = 0
while not mvfncs[drctn][1]() do
if mvfncs[drctn][2]() then
if not mvfncs[drctn][3]() then trply("unbreakable block in path") return false end
elseif turtle.getFuelLevel() == 0 then trply("Out of fuel" ) return false
else mvfncs[drctn][4]() end
if itr8 > 64 then trply("persistent impediment") return false end
itr8 = itr8+1
end
return true
end
local rctfncs = {
tnl = function() turtle.digUp() turtle.digDown() return mvdgK(1) end,
dfd = function() return mvdgK(1) end,
dup = function() return mvdgK(2) end,
ddn = function() return mvdgK(3) end,
bmb = function()
if turtle.placeDown() then redstone.setOutput("bottom",true)
sleep(0.5) redstone.setOutput("bottom",false)
if not turtle.detectDown() then return true end end
return false end,
pckup = function() if turtle.suck() then return turtle.suckUp() else return turtle.suckDown() end end,
chst = function()
turtle.select(16)
if turtle.place() then for i = 1,15 do turtle.select(i) turtle.drop() end return true end
return false end,
slct = function()
cldt.slt = math.fmod(cldt.slt,16)+1
turtle.select(cldt.slt)
local stcksz = turtle.getItemCount(cldt.slt)
return "Slot "..cldt.slt..", "..stcksz.."/"..stcksz+turtle.getItemSpace(cldt.slt)
end,
rfl = function()
turtle.select(cldt.slt)
trply("Current fuel level is "..turtle.getFuelLevel())
if turtle.refuel() then return "New fuel level is "..turtle.getFuelLevel()
else return false end
end,
gox = function(cmmnds)
cmmnds = cmmnds:match("%S+")
return tfnctns[6](cmmnds)
end,
gpslct = function() local x,y,z = gps.locate(2) if x then return "GPS = "..x..", "..y..", "..z
else return false end end,
gpshst = function()
local tp = {gps.locate(2)}
if tp[1] then trply("Serving GPS from "..tp[1]..", "..tp[2]..", "..tp[3]) end
repeat tp[4],tp[5],tp[6] = rednet.receive()
if tp[5] == "PING" then rednet.send(tp[4], textutils.serialize({tp[1],tp[2],tp[3]}))
trply("PINGed by "..tp[4].." at "..tp[6].." meters")
elseif cldt.rcID == tp[4] and tp[5] == "gpshst" then tp[1] = nil end
until not tp[1]
return "GPS hosting terminated"
end,
rcvfl = function(flnm)
local cntnt
flnm,cntnt = flnm:match("(%S+)%s*(.*)")
local hndl = fs.open(flnm,"w") hndl.writeLine(cntnt) hndl.close()
return flnm.." updated" end,
srvfl = function(flnm)
flnm = flnm:match("%S+")
local flbdy = fs.open(flnm,"r")
trply(flbdy.readAll()) flbdy.close()
return flnm.." served" end,
xqtfl = function(prms)
local tprm,ndx = {},1
for v in prms:gmatch("%w+") do tprm[ndx] = v ndx = ndx+1 end
shell.run(unpack(tprm))
local hndl = fs.open("startup","w")
hndl.writeLine("shell.run("clfn",1,"..cldt.rcID..")") hndl.close()
return tprm[1].." executed" end,
ldstrng = function(luacd)
local tmpfnc,rrmssg = loadstring(luacd)
if tmpfnc then return tmpfnc()
else return rrmssg end
end,
}
local cmdlst = {f=rctfncs.dfd,b=turtle.back,u=rctfncs.dup,d=rctfncs.ddn,
l=turtle.turnLeft,r=turtle.turnRight,t= rctfncs.tnl,
p=turtle.place,P=turtle.placeUp,o=turtle.placeDown,
x=turtle.drop,X=turtle.dropUp,z=turtle.dropDown,
e=turtle.dig,E=turtle.digUp,w=turtle.digDown,
v=rctfncs.pckup,V=turtle.suckUp,c=turtle.suckDown,
R=rctfncs.rfl,S=rctfncs.slct,B=rctfncs.bmb,C=rctfncs.chst
}
tfnctns = {
function(rtID)
cldt.rcID = tonumber(rtID)
rednet.open("right")
if cldt.rcID then cldt.slt = 1 turtle.select(cldt.slt) else
write("Enter controller ID> ") cldt.rcID = tonumber(read())
end
print("Turtle "..os.computerID().." controlled by console "..cldt.rcID)
local hndl = fs.open("startup","w")
hndl.writeLine("shell.run("clfn",1,"..cldt.rcID..")") hndl.close()
while cldt.rcID do
repeat cldt[1],cldt[2] = rednet.receive() until cldt[1] == cldt.rcID
cldt[3], cldt[4] = cldt[2]:match("^(%a+)%s*(.*)")
if cldt[4] == "" then cldt[4] = "1" end
if turtle[cldt[3]] then trply(tostring(turtle[cldt[3]](tonumber(cldt[4]))))
elseif rctfncs[cldt[3]] then trply(tostring(rctfncs[cldt[3]](cldt[4])))
elseif cldt[2] == "trmn8RC" then trply("Remote Control Terminated")
cldt.rcID = nil
end
end
end,
function()
cldt.slt = 16
write("Place fuel in Slot 16 and enter") read()
print(cmdlst.R())
end,
function()
write("Place material to be sifted in Slots 1-15nLeave Slot 16 empty") read()
repeat
turtle.place()
if turtle.getItemCount(cldt.slt) < 1 then rctfncs.slct() end
if not turtle.dig() then print("Error") break end
until cldt.slt > 15
end,
function()
write("Place seeds in Slot 1nBonemeal in Slots 2-15nLeave Slot 16 empty") read()
cldt.slt = 2
repeat
turtle.select(1)
if not turtle.place() then print("There must be tilled dirt to plant") break end
turtle.select(cldt.slt)
if not turtle.place() then print("Process requires Bonemeal to continue") break end
if turtle.getItemCount(cldt.slt) < 1 then rctfncs.slct() end
turtle.dig()
until cldt.slt > 15
end,
function(x3Ps,z3Ps,fcng,dmn)
x3Ps,z3Ps,fcng,dmn = tonumber(x3Ps),tonumber(z3Ps),tonumber(fcng),tonumber(dmn)
local x1Ps,y1Ps,z1Ps,x2Ps,z2Ps = 0,255,0,1,0
local cntntstng = [[fs.copy("disk/rnhst","rnhst") shell.run("rnhst","host",]]
if fs.exists("rom/programs/rnhst") then cntntstng = [[shell.run("rnhst","host",]]
elseif not fs.exists("rnhst") then print("Must have available rnhst program to execute")
return false end
local function gpsnode(xPos,yPos,zPos)
turtle.select(2) cmdlst.p()
turtle.select(4) cmdlst.x()
if fs.exists("rnhst") and not fs.exists("disk/rnhst") then fs.copy("rnhst","disk/rnhst") end
local strtfl = fs.open("disk/startup","w")
strtfl.writeLine(cntntstng..xPos..","..yPos..","..zPos..","..dmn..")")
strtfl.close()
local cmdstrng = {"u","f","l","b",}
for i = 1,#cmdstrng do cmdlst[cmdstrng[i]]() end
turtle.select(1) cmdlst.p() cmdlst.b()
turtle.select(3)
cmdstrng = {"p","l","f","r","f","f","r",}
for i = 1,#cmdstrng do cmdlst[cmdstrng[i]]() end
peripheral.call("front","turnOn")
cmdlst.d() cmdlst.v()
end
local function plcaxis(xPos,yPos,zPos)
x1Ps,y1Ps,z1Ps = gps.locate(2,true)
cmdlst.f()
if x1Ps then --there is a GPS system, use it to determine coordinates and facing
x2Ps,yPos,z2Ps = gps.locate(2)
x2Ps,z2Ps = x2Ps-x1Ps,z2Ps-z1Ps
else x1Ps,y1Ps,z1Ps = xPos,yPos,zPos end
cmdlst.d()
gpsnode(x1Ps+(x2Ps*2),y1Ps,z1Ps+(z2Ps*2))
-- Go back 2 and set the second node
cmdlst.r() cmdlst.r()
for c=1,2 do turtle.forward() end
gpsnode(x1Ps-(x2Ps*2),y1Ps,z1Ps-(z2Ps*2))
end
while not(x3Ps and z3Ps and fcng and dmn) do
write([[Fill inventory as follows
Slot 1 > 4+ Computers
Slot 2 > 4+ Disk drives
Slot 3 > 4+ Wireless Modems (4x)
Slot 4 > Floppy disk
Enter turtle's current x> ]]) x3Ps = tonumber(read())
write("Enter turtle's current z> ") z3Ps = tonumber(read())
write("Enter turtle's current facing> ") fcng = tonumber(read())
write("Enter initial admin access ID") dmn = tonumber(read())
end
for i=1, fcng+1 do turtle.turnLeft() end
while turtle.getFuelLevel() < 500 do
trply("Low Fuel Warning!")
write("Place fuel in Slot 16 and press Enter") read()
cldt.slt = 16 print(cmdlst.R())
end
-- launch turtle
while cmdlst.u() do end
plcaxis(x3Ps,255,z3Ps)
-- Go back to the middle and turn
x2Ps,z2Ps = 0,1
cmdlst.b() cmdlst.r()
plcaxis(x3Ps,254,z3Ps)
cmdlst.b()
while turtle.down() do end
end,
function(cmndstrng) -- Go commands
-- non-nil array length
local function lngth(lst)
if lst then return #lst else return 0 end
end
local function gtNmbr(strg)
local nmbr,rmndr = strg:match("^(%d+)(.*)$")
return nmbr,lngth(strg)-lngth(rmndr)
end
local function gtLoop(strg)
local loop,rmndr = strg:match("^(%b[])(.*)$")
if loop then return loop:sub(2,-2),lngth(strg)-lngth(rmndr)
else return nil,0 end
end
local function gox(cmnds)
if not #cmnds then return false end
local ndx,prvCmnd,result = 1,""
while ndx <= #cmnds do
local char = cmnds:sub(ndx,ndx)
local nxtCh = cmnds:sub(ndx+1, ndx+1)
if cmdlst[char] then
ndx,result = ndx+1,cmdlst[char]()
else
local nmbr, nLen = gtNmbr(cmnds:sub(ndx))
local loop, lpLen = gtLoop(cmnds:sub(ndx))
if nmbr then
for i = 2,tonumber(nmbr) do gox(prvCmnd) end
ndx = ndx+nLen
elseif loop then
local nmbr, nLen = gtNmbr(cmnds:sub(ndx+lpLen))
if nmbr then
for i = 1,tonumber(nmbr) do gox(loop) end
ndx = ndx+nLen
else while gox(loop) do end end
ndx = ndx+lpLen
end end
prvCmnd = char
end
return result
end
if not cmndstrng then
print([[enter a string of commands/loops
f b u d l r to move, t to tunnel
p P o to place[U/Dn], x X z to drop
e E w to dig [U/Dn], v V c to suck
R to refuel, S to select next slot
[...] loop while last command succeeds
number for fixed loop]])
cmndstrng = read() end
return gox(cmndstrng)
end,
}
shell.run('clear')
cldt[1] = tonumber(tArgs[1])
if cldt[1] and tArgs[2] then tfnctns[cldt[1]](unpack(tArgs,2)) else
repeat
cldt.slt = 1
turtle.select(cldt.slt)
print("Select function by number")
print([[1: Remote Control
2: Refuel
3: Sift Gravel
4: Auto Farm
5: Launch GPS Array
6: GoX commands
Or other to exit]])
sclfn = tfnctns[tonumber(read())]
if sclfn then sclfn() end
until not sclfn
end
On the other hand, if you spot areas where the functionality (not just the notation style) of the code can be improved, please share.
Oh, I should include the program for controlling a turtle remotely. It isn't strictly necessary (you can just send the commands by rednet in lua mode), but it could be helpful.
Spoiler
local tvnt,cnslID,rcID = {},os.computerID()
local rcmdlst = {
[0] = "bmb",[79] = "place",[80] = "back",[81] = "ddn",[75] = "turnLeft",[76] = "tnl",
[77] = "turnRight",[71] = "placeUp",[72] = "dfd",[73] = "dup",[82] = "placeDown",
[83] = "drop8",[74] = "rfl",[78] = "slct",[181] = "gpshst",[55] = "gpslct",[28] = "pckup",
[210] = "place",[211] = "dig",[199] = "chst",[207] = "suck",[201] = "up",[209] = "down",
[200] = "forward",[208] = "back",[203] = "turnLeft",[205] = "turnRight",[26] = "digUp",
[27] = "digDown",[51] = "suckUp",[52] = "suckDown",[29] = "trmn8RC",
}
local function opnmdm()
for i,v in pairs(rs.getSides()) do
if peripheral.getType(v) == "modem" then
if not rednet.isOpen(v) then rednet.open(v) end
return true end
end
return false end
local function pntxt(x,y,txt) term.setCursorPos(x,y) write(txt) end
local mnutxt = {"Access Control","Transmit file","Receive file","Find GPS Hosts","Exit Menu",}
local mnufnc = {
function () local tp = {}
pntxt(1,6,"Enter an ID to alter access level for it on rnhst"..rcID) tp[2] = read()
write("add or ban this ID?")
repeat tp[1] = read() if tp[1]:find("^[aA]") then
tp[1] = "add" elseif tp[1]:find("^[bB]") then tp[1] = "ban" end
until tp[1] == "add" or tp[1] == "ban"
write("Change Admin or User list?")
repeat tp[3] = read() if tp[3]:find("^[aAdD]") then
tp[3] = "dmnlst" elseif tp[3]:find("^[uUxX]") then tp[3] = "xclst" end
until tp[3] == "dmnlst" or tp[3] == "xclst"
print(cnslID..">"..rcID..": access "..tp[1].." "..tp[2].." "..tp[3])
rednet.send(rcID,"access "..tp[1].." "..tp[2].." "..tp[3])
return 1 end,
function () local tp = {}
pntxt(1,6,"Enter name of file to send")
repeat tp[1] = read() until fs.exists(tp[1])
tp[2] = fs.open(tp[1],"r") tp[3] = tp[2].readAll() tp[2].close()
print(cnslID..">"..rcID..": "..tp[1].." by FTP")
rednet.send(rcID,"flrcv "..tp[1].." "..tp[3])
return 3 end,
function () local tp = {}
pntxt(1,6,"Enter name of file to get") tp[1] = read()
rednet.send(rcID,"flsrv "..tp[1])
print(rcID..">"..cnslID..": "..tp[1].." by FTP")
repeat tp[2],tp[3] = rednet.receive(1) until tp[2] == rcID or not tp[2]
if tp[2] then tp[4] = fs.open(tp[1],"w") tp[4].writeLine(tp[3]) tp[4].close()
else write("Could not get file") end
return 2 end,
function () local tp = {} rednet.send(rcID,"hsts")
pntxt(1,6,"Getting Host data from "..rcID)
repeat tp[1],tp[2] = rednet.receive(3) until tp[1] == rcID and tp[2] ~= "PING" or not tp[1]
if tp[1] then tp[3] = fs.open("GPSHSTS"..rcID,"w") tp[3].writeLine(tp[2]) tp[3].close()
print("Saving data as GPSHSTS"..rcID)
else print("Could not get file") end
return 5 end,
function () pntxt(1,6,"Exiting Menu") return nil end,
}
local function menu() local ndx = 1
term.clear() pntxt(1,6,"Use up/down to select option")
repeat for i = 1,5 do pntxt(1,i," "..mnutxt[i]) end pntxt(1,ndx,">")
tvnt = {os.pullEvent()}
if tvnt[1] == "key" and (tvnt[2] == 200 or tvnt[2] == 201) then
ndx = math.fmod(ndx+3,5)+1
elseif tvnt[1] == "key" and (tvnt[2] == 208 or tvnt[2] == 209) then
ndx = math.fmod(ndx,5)+1
elseif tvnt[1] == "key" and tvnt[2] == 28 then ndx = mnufnc[ndx]()
elseif tvnt[1] == "rednet_message" then
pntxt(1,6,"Message from "..tvnt[2]) print(tvnt[3])
end
until not ndx
end
local function setID() write("Enter receiver ID> ") return tonumber(read()) end
shell.run('clear')
if not opnmdm() then print("Modem Access Error") return false end
repeat rcID = setID() until rcID
write("Receiver ID set to "..rcID)
print("Press "h" for help")
repeat
tvnt = {os.pullEvent()}
if tvnt[1] == "key" and rcmdlst[tvnt[2]] then rednet.send(rcID,rcmdlst[tvnt[2]])
if tvnt[2] == 29 then rcID = setID() end
elseif tvnt[1] == "rednet_message" then print(tvnt[2]..": "..tvnt[3])
if tvnt[3]:find("^send") then rednet.send(tvnt[2],read()) end
elseif tvnt[2] == "S" then rednet.send(rcID,read())
elseif tvnt[2] == "R" then rcID = setID()
elseif tvnt[2] == "M" then menu()
elseif tvnt[2] == "h" or tvnt[2] == "H" then
print([[Use "R" change receiver ID
Use "S" to send text string
Change receiver to nil to exit rcpda
Use numberpad to control turtles:
284693 to digmove, 5 to tunnel
170 to place, '.' Home End, to drop
Enter, <, >, to suck
Del, [, ] to dig
Direction Keys and PgUp/Dn to move
lCtrl to exit]])
end
until not rcID
User/customization guide for rctrl, also substantially applicable to rcpda:
Spoiler
When started, rctrl tries to open a modem, if it can't find one, it prints "Modem Access Error" and returns false. if it does find one, it prompts you do enter a receiver ID. This can be a wireless turtle running clfn remote control or an rnhst node, or anything really, but most of the programs options will be pretty useless. You can of course just use the rednet send/receive functionality to chat with someone else running rctrl or some other rednet messaging program, but that is not optimal (you'll tend to miss some messages while inputting yours).Anyhow, once you enter a number to be the receiver ID (and the program won't accept anything else, so enter a number), you'll see the message:"Receiver ID set to ID Press "h" for help" (where ID is the number you put in. If you press h, you'll get the help text for key command of a clfn turtle. It looks like this:
Use "R" change receiver ID
Use "S" to send text string
Change receiver to nil to exit rcpda
Use numberpad to control turtles:
284693 to digmove, 5 to tunnel
170 to place, '.' Home End, to drop
Enter, <, >, to suck
Del, [, ] to dig
Direction Keys and PgUp/Dn to move
lCtrl to exit
Note: the rcpda help is similar but formatted differently due to the restrictions of the PDA screen.
"R" and "S" mean the capital letter, so use Shift+R and Shift+S to activate these options. The turtle command keys should work pretty much as described on most keyboards.
A word about changing the receiver ID or sending a text message, while you're doing either you can miss incoming rednet messages. If you want to use a computer as a monitor to collect all incoming messages, then you'll need a different program. But for basic control of clfn remote turtles or rnhst nodes this is not a major concern.
The heart of turtle control is really the key controls, to instantly send pre-configured command messages to a clfn turtle. This is controlled through a table called rcmdlst, defined right up near the top of the program (in the rctrl program, it is actually quite far down in the rcpda program file, past a bunch of functions that you probably don't want to muck about with unless you are confident in your programming skills). If you want to modify the key mapping, it's quite easy. The table looks like this:
local rcmdlst = {
[0] = "bmb",[79] = "place",[80] = "back",[81] = "ddn",[75] = "turnLeft",[76] = "tnl",
[77] = "turnRight",[71] = "placeUp",[72] = "dfd",[73] = "dup",[82] = "placeDown",
[83] = "drop8",[74] = "rfl",[78] = "slct",[181] = "gpshst",[55] = "gpslct",[28] = "pckup",
[210] = "place",[211] = "dig",[199] = "chst",[207] = "suck",[201] = "up",[209] = "down",
[200] = "forward",[208] = "back",[203] = "turnLeft",[205] = "turnRight",[26] = "digUp",
[27] = "digDown",[51] = "suckUp",[52] = "suckDown",[29] = "trmn8RC",
}
All you need to do to change the key mapping of an existing command is to change the keycode value next to the command. A standard keymap is here. If you want to have, say, the B key issue the "bmb" command, then just change '[0] = "bmb",' to '[48] = "bmb",' and you have a different "bmb" key. Two points to note. First, you must use the numeric key code, not the character. The second point is that you cannot have two different commands issued by the same key (there is a way around this, which is to have a key that activates "gox fbudlrBS" or something like that, replace "fbudlrBS" with the commands you actually want activated by that key, in the sequence you want them activated, but it is still a single gox command). You may, on the other hand, have two different keys activate the same command. I have the turnLeft/Right commands on both the arrow keys and the numberpad, and there are other duplicates as well. Perhaps it would be more appropriate to have the numberpad left-4/right-6 keys mapped to "gox lf" and "gox rf" respectively. It's entirely valid.Because the keys are activated in the same loop that checks for rednet messages, key control never interferes with rednet reception. You'll get all rednet messages sent to you (even by different turtles or nodes than the one your currently controlling). But the limits of key control, that a particular key is mapped to a particular command, means that it is unsuitable for commands that require complex variable input (like a ldstrng command, or most of the rnhst commands).
There is a menu available for friendlier (I hope) usage of the more difficult rnhst functions. The menu is accessed by pressing Shift+M (this is also a character event based selection, like "R" and "S"). It should be relatively self-explanitory, if it is not, then give some feedback on how it can be improved (usability only, no snazzy graphics suggestions, which I find tend to reduce readability anyway).
The use of "S" to enter a rednet text message is essential for complex gox usage, as well as the less frequent (I hope) use of srvfl, rcvfl, xqtfl, and ldstrng. Since these commands require additional parameters in their strings, it is probably impractical to have them mapped to keys in most cases (though I noted an exception for gox above).
Using "R" to change the current turtle controlled is also quite important, unless you are using an rnhst node relay to boost range to your turtles, in which case you'll be switching control of the current turtle using "S" to send "rly ID" (where ID is the turtle ID) to the rnhst node to switch control.
Hopefully this guide helps you get the most out of rctrl, and helps you hunt out bugs. If something doesn't work the way this says it should, then report it!
The code has been updated and now provides the ability for the remote control terminal to send entered strings, and the remote turtle will now accept loadstring commands (Shift+s to enter text send, send "loadstring", when the turtle gets the command you'll be prompted to "send lua code chunk"). If the text is not valid lua code then you'll get back the error message, but if you send syntactically valid lua code that produces an error then the remote control function will terminate. The functions "rcvfl" and "srvfl" have also been added, so that you can remotely write/read files on the turtle (or on a disk in a drive next to the turtle).
The code has been updated again and now supports passing a numeric variable to the turtle API commands. This means that you can now use turtle.select(n) by sendind "select n" (where n is the number of the slot to select). The turtle also responds to all turtle commands by reporting the function result (if any). The "loadstring" command has been replaced by "ldstrng" (to avoid confusion in the code). I think there were also some other minor improvements, but don't remember what they are.
Fixed inability to remote terminate remote control.
Early versions of clfn and rctrl posted on pastebin. Newer versions are in development, later in the thread. These will be posted to pastebin after some more development and testing.
Newest versions of clfn and rctrl now posted. There is also a version of rctrl that utilizes the CCPortable pda, named rcpda. The newest version of clfn is designed to work with rnhst, in development in the Programs forum (specifically, the Launch GPS Array functionality now launches an array of rnhst nodes rather than standard gps nodes). If you cannot (or just don't wish to) install rnhst in rom, then a copy has to be on the turtle that places the array (this is also useful because turtles can be used as temporary rnhst nodes themselves). The copy on the turtle will be copied to the disk and thence to the computers in the array.
Mad props to Ralnick for patient testing of bugged versions, the latest bugfix/update is up.
Experimental rcpda with menu for easy access to rnhst options, and now the ability to use up/down and PgUp/PgDn keys to revisit previous inputs (and returns) when sending text. Feedback always welcome. Another new version of clfn, this one adds a chst command that places a block from slot 16 and attempts to dump the rest of the inventory into it. It can be used with gox as "C". Bugfix/update for clfn (bugs discovered while reading the code to create the user guide, none found in "chst"/"C"), new updates for latest rcpda and rctrl.
Further development will require separation into an api and other parts, and thus clfn will no longer be an integrated, standalone program. Therefore, this will probably be the final update for the standalone clfn, barring the discovery of any further bugs, which I shan't be doing because I'll be using an api based collection of programs I'm developing.