ControlMe - Remote control for your turtle!
Description
ControlMeControl your turtle with a pocket computer!Spoiler[attachment=2477:ControlMe Interface.PNG](This is obviously the pocket computer, the turtle doesn't have an interface)DownloadWireless Advanc...
Installation
Copy one of these commands into your ComputerCraft terminal:
Pastebin:
pastebin get mTGccYbM controlme_-_remote_control_for_your_turtle!wget:
wget https://pastebin.com/raw/mTGccYbM controlme_-_remote_control_for_your_turtle!Archive:
wget https://cc.shobie.xyz/cc/get/pb-mTGccYbM controlme_-_remote_control_for_your_turtle!
Quick Install:
wget https://cc.shobie.xyz/cc/get/pb-mTGccYbM ControlMe - Remote control for your turtle!
Usage
Run the program after downloading
Tags
Source
View Original SourceCode Preview
--[[
HPWebcamAble presents...
ControlMe
--=== Description ===--
This program lets you control a turtle from a pocket computer!
This version of the program is for the POCKET COMPUTER
Get the Turtle version here: pastebin.com/zjn3E5LS
--=== Installation ===--
Pastebin Code: mTGccYbM
To download a file from pastebin, run this command in a computer:
pastebin get <code> <file name>
--=== Update History ===--
The pastebin will always have the most recent version
|1.0|
-Release
]]
--=== Variables ===--
local args = {...}
local protocalName = "controlme"
local turtleID
local w,h = term.getSize()
local tools = {}
local knownTools = {
["modem"] = {text = "Modem", upAndDown = false},
["minecraft:diamond_pickaxe"] = {text = "Mine", upAndDown = true, action = "turtle.dig"},
["minecraft:diamond_sword"] = {text = "Attack", upAndDown = true, action = "turtle.attack"},
["minecraft:diamond_hoe"] = {text = "Hoe", upAndDown = true, action = "turtle.dig"},
["minecraft:diamond_axe"] = {text = "Chop", upAndDown = true, action = "turtle.dig"},
["minecraft:diamond_shovel"] = {text = "Dig", upAndDown = true, action = "turtle.dig"}
}
local turtleImage = [[ffffffffff
f77777777f
f77ffff77f
f77777777f
f88888888f
f88888888f
ffffffffff
]]
local inventoryImage = [[77777777777777777
78887888788878887
78887888788878887
77777777777777777
78887888788878887
78887888788878887
77777777777777777
78887888788878887
78887888788878887
77777777777777777
78887888788878887
78887888788878887
77777777777777777
]]
-- Load Images
do
local f = fs.open("temp","w") f.write(turtleImage) f.close()
turtleImage = paintutils.loadImage("temp")
f = fs.open("temp","w") f.write(inventoryImage) f.close()
inventoryImage = paintutils.loadImage("temp") fs.delete("temp")
end
--=== Functions ===--
local function color(text,back)
local temp = text and term.setTextColor(text) or nil
temp = back and term.setBackgroundColor(back) or nil
end
local function printC(text,y)
if type(text) ~= "string" or type(y) ~= "number" then error("expected string,number, got "..type(text)..","..type(y),2) end
local lenght = #text
local start = math.floor((w-lenght)/2)+1
term.setCursorPos(start,y)
term.write(text)
return start,start+lenght
end
-- These functions are from my Screen API
-- http://pastebin.com/4j4mJsWw
local default = {
object = {
text = nil,
name = "default",
minX = 1,minY = 1,
maxX = 7,maxY = 3,
states = {
on = {text = colors.white, back = colors.lime},
off = {text = colors.white, back = colors.red}
},
clickable = false,
visible = true,
state = "off",
action = nil
},
clickArea = {
name = "default",
minX = 1,minY = 1,
maxX = 5,maxY = 3,
clickable = true,
action = nil
}
}
local function fillTable(toFill,fillWith) --Used by the API
if toFill == nil then toFill = {} end
for a,b in pairs(fillWith) do
if type(b) == "table" then
toFill[a] = fillTable(toFill[a],b)
else
toFill[a] = toFill[a]==nil and b or toFill[a]
end
end
return toFill
end
local function countIndexes(tbl) --Also used by API
local total = 0
for a,b in pairs(tbl) do total = total+1 end
return total
end
local function assert(check,err,lvl)
lvl = lvl or 2
if not check then error(err,lvl+1) end
return check
end
function new(nBackground)
local api = {}
local objects = {}
local clickAreas = {}
local background = nBackground
function api.checkPos(x,y)
x,y = tonumber(x),tonumber(y)
assert(x and y,"expected number,number")
for name,data in pairs(clickAreas) do
if x >= data.minX and x <= data.maxX and y >= data.minY and y <= data.maxY and data.clickable then
if type(data.action)=="function" then return true,true,data.action()
else return true,false,"click_area",name end
end
end
for name,data in pairs(objects) do
if data.clickable and data.visible and x >= data.minX and x <= data.maxX and y >= data.minY and y <= data.maxY then
if type(data.action)=="function" then return true,true,data.action()
else return true,false,"object",name end
end
end
return false
end
function api.handleEvents(bUseRaw)
local pull = bUseRaw and os.pullEventRaw or os.pullEvent
local event = {pull()}
if event[1] == "mouse_click" then
local wasElement,hadFunction,elementType,name = api.checkPos(event[3],event[4])
if wasElement then
if not hadFunction then
return elementType,name,event[2]
else return nil
end
end
end
return unpack(event)
end
function api.setDefaultObject(newDefaultObject)
assert(type(newDefaultObject)=="table","expected table, got "..type(newDefaultObject))
default.object = fillTable(newDefaultObject,default.object)
end
function api.setDefaultClickArea(newDefaultClickArea)
assert(type(newDefaultClickArea)=="table","expected table, got "..type(newDefaultClickArea))
default.clickArea = fillTable(newDefaultClickArea,default.clickArea)
end
function api.draw()
if background then term.setBackgroundColor(background) term.clear() end
for name,data in pairs(objects) do
api.drawObject(name)
end
end
function api.addClickArea(clickAreaInfo)
assert(type(clickAreaInfo)=="table","expected table, got "..type(clickAreaInfo))
fillTable(clickAreaInfo,default.clickArea)
assert(clickAreas[clickAreaInfo.name]==nil,"an object with the name '"..clickAreaInfo.name.."' already exists")
clickAreas[clickAreaInfo.name] = clickAreaInfo
end
function api.toggleClickArea(name)
assert(clickAreas[name]~=nil,"Click Area '"..name.."' doesn't exist")
clickAreas[name].clickable = not clickAreas[name].clickable
return clickAreas[name].clickable
end
function api.getClickArea(name)
assert(clickAreas[name]~=nil,"Click Area '"..name.."' doesn't exist")
return clickAreas[name]
end
function api.addObject(objectInfo)
assert(type(objectInfo)=="table","expected table, got "..type(objectInfo))
objectInfo = fillTable(objectInfo,default.object)
assert(objects[objectInfo.name]==nil,"an object with the name '"..objectInfo.name.."' already exists")
objects[objectInfo.name] = objectInfo
end
function api.drawObject(name)
assert(objects[name]~=nil,"Object '"..name.."' doesn't exsist")
local objData = objects[name]
if objData.visible == false then return end
assert(objData.states~=nil,"Object '"..name.."' has no states!")
assert(objData.states[objData.state],"Object '"..name.."' doesn't have state '"..objData.state.."'")
term.setBackgroundColor(objData.states[objData.state].back)
term.setTextColor(objData.states[objData.state].text)
for i = 0, objData.maxY-objData.minY do
term.setCursorPos(objData.minX,objData.minY+i)
term.write(string.rep(" ",objData.maxX-objData.minX+1))
end
if objData.text then
local xPos = objData.minX+math.floor(((objData.maxX-objData.minX+1)-#objData.text)/2)
local yPos = objData.minY+(objData.maxY-objData.minY)/2
term.setCursorPos(xPos,yPos) term.write(objData.text)
end
end
function api.toggleObjectState(name) -- Only works if an object has two states
assert(objects[name]~=nil,"Object '"..name.."' doesn't exist")
assert(countIndexes(objects[name].states)==2,"Object '"..name.."' can't be toggled, it doesn't have two states")
curState = objects[name].state
for a,b in pairs(objects[name].states) do
if a ~= curState then
objects[name].state = a
end
end
return objects[name].state
end
function api.setObjectState(name,state)
assert(objects[name] ~= nil,"Object '"..name.."' doesn't exist")
assert(objects[name].states[state],"Object '"..name.."' doesn't have state '"..state.."'")
objects[name].state = state
end
function api.getObject(name)
assert(objects[name] ~= nil,"Object '"..name.."' doesn't exist")
return objects[name]
end
function api.toggleObjectVisible(name)
assert(objects[name] ~= nil,"Object '"..name.."' doesn't exist")
objects[name].visible = not objects[name].visible
return objects[name].visible
end
function api.toggleObjectClickable(name)
assert(objects[name] ~= nil,"Object '"..name.."' doesn't exist")
objects[name].clickable = not objects[name].clickable
return objects[name].clickable
end
return api
end
-- End Screen API
local function checkMessage(event,skipTableCheck,skipIDCheck)
return event[4] == protocalName and (skipTableCheck or type(event[3]) == "table") and (skipIDCheck or event[2] == turtleID)
end
local function message(message)
rednet.send(turtleID,message,protocalName)
end
local function broadcast(message)
rednet.broadcast(message,protocalName)
end
local function execute(func,waitTime)
message({action="execute",func=func})
local timer = waitTime and os.startTimer(waitTime) or "done"
local completed = false
while true do
local event = {os.pullEvent()}
if event[1] == "rednet_message" and checkMessage(event) and event[3].action == "completed" then
if timer == "done" then return event[3].result
else completed = true end
elseif event[1] == "timer" and timer == event[2] then
if completed then break
else timer = "done" end
end
end
end
local function getModem()
for a,b in pairs(rs.getSides()) do
if peripheral.getType(b) == "modem" and peripheral.call(b,"isWireless") then
return b
end
end
end
local function waitForMessage(skipTableCheck,skipIDCheck)
while true do
local event = {os.pullEvent("rednet_message")}
if checkMessage(event,skipTableCheck,skipIDCheck) then
return event[3]
end
end
end
-- Create the screen
local mainScreen = new()
local function action(buttonName,func,waitTime)
mainScreen.getObject(buttonName).state = "active" mainScreen.drawObject(buttonName)
execute(func,waitTime or 0.5)
mainScreen.getObject(buttonName).state = "on" mainScreen.drawObject(buttonName)
end
local function forward()
action("forward","turtle.forward()")
end
local function turnLeft()
action("turnLeft","turtle.turnLeft()")
end
local function turnRight()
action("turnRight","turtle.turnRight()")
end
local function back()
action("back","turtle.back()")
end
local function up()
action("up","turtle.up()")
end
local function down()
action("down","turtle.down()")
end
local drawMainScreen
local function options()
-- Silly animition that I love so please don't question it
for i = 0, 12 do
color(colors.white,colors.blue) term.clear()
paintutils.drawImage(turtleImage,9,7-(i/2))
color(colors.white,colors.green) term.setCursorPos(1,h-i) term.clearLine() printC("Options",h-i)
color(colors.white,colors.brown)
for a = 0, i-1 do
term.setCursorPos(1,h-a) term.clearLine()
end
sleep(0.1)
end
color(colors.black,colors.lightGray)
printC(" ",10)
printC(" Disconnect ",11)
printC(" and Exit ",12)
printC(" ",13)
printC(" ",15)
printC(" Back ",16)
printC(" ",17)
while true do
local event = {os.pullEvent("mouse_click")}
if event[4] == 10 or event[4] == 11 or event[4] == 12 or event[4] == 1 then
error()
elseif event[4] == 16 or event[4] == 15 or event[4] == 17 then
break
end
end
for i = 12, 0, -1 do
color(colors.white,colors.blue) term.clear()
paintutils.drawImage(turtleImage,9,7-(i/2))
color(colors.white,colors.green) term.setCursorPos(1,h-i) term.clearLine() printC("Options",h-i)
color(colors.white,colors.brown)
for a = 0, i-1 do
term.setCursorPos(1,h-a) term.clearLine()
end
sleep(0.1)
end
drawMainScreen()
end
-- Add buttons
--mainScreen.addObject({name="inventory", minX=10, maxY=12, state="default", maxX=17, clickable=false, visible=true, states={default={text=1,back=256,},}, minY=11, text="View Inv", })
mainScreen.addObject({name="turnRight", minX=20, maxY=18, state="on", maxX=25, clickable=true, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, minY=16, text="Turn R", action=turnRight})
mainScreen.addObject({name="actionLeft", minX=20, maxY=11, state="on", maxX=26, clickable=false, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, text="No Tool", minY=9, })
mainScreen.addObject({name="turnLeft", minX=2, maxY=18, state="on", maxX=7, clickable=true, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, minY=16, text="Turn L", action=turnLeft})
mainScreen.addObject({name="actionRightDown", minX=3, maxY=13, state="on", maxX=7, clickable=false, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, minY=13, text="v", })
mainScreen.addObject({name="actionRight", minX=1, maxY=11, state="on", maxX=7, clickable=false, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, minY=9, text="No Tool", })
mainScreen.addObject({name="back", minX=9, maxY=17, state="on", maxX=18, clickable=true, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, minY=15, text="Backward", action=back})
mainScreen.addObject({minY=20, minX=1, state="default", maxY=20, maxX=26, clickable=true, visible=true, states={default={text=1,back=8192,},}, name="options", text="Options", action = options})
mainScreen.addObject({name="actionRightUp", minX=3, maxY=7, state="on", maxX=7, clickable=true, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, minY=7, text="^", })
mainScreen.addObject({name="actionLeftDown", minX=20, maxY=13, state="on", maxX=24, clickable=false, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, text="v", minY=13, })
mainScreen.addObject({name="down", minX=20, maxY=4, state="on", maxX=25, clickable=true, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, text="Down", minY=2, action=down})
mainScreen.addObject({name="up", minX=2, maxY=4, state="on", maxX=7, clickable=true, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, text="Up", minY=2, action=up})
mainScreen.addObject({name="actionLeftUp", minX=20, maxY=7, state="on", maxX=24, clickable=false, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, text="^", minY=7, })
mainScreen.addObject({name="forward", minX=9, maxY=5, state="on", maxX=18, clickable=true, visible=true, states={off={text=1,back=256,},on={text=32768,back=1,},active={text=1,back=32,},}, minY=3, text="Forward", action=forward})
-- Function to draw the screen
drawMainScreen = function()
color(nil,colors.blue) term.clear()
paintutils.drawImage(turtleImage,9,7)
mainScreen.draw()
end
local function getFreeSlot()
for i = 1, 16 do
local result = execute("turtle.getItemCount("..i..")")
if result == 0 then
return i
end
end
return false
end
local function showToolName(name,side)
local obj = mainScreen.getObject("action"..side)
local up = mainScreen.getObject("action"..side.."Up")
local down = mainScreen.getObject("action"..side.."Down")
if knownTools[name] then
obj.text = knownTools[name].text
obj.state = "on"
obj.clickable = true
if knownTools[name].action then
obj.action = function() action("action"..side,knownTools[ tools.left ].action.."()",0.2) end
end
mainScreen.drawObject("action"..side)
if knownTools[name].upAndDown then
up.state = "on"
up.clickable = true
up.action = function() action("action"..side.."Up",knownTools[name].action.."Up()",0.2) end
down.state = "on"
down.clickable = true
down.action = function() action("action"..side.."Down",knownTools[name].action.."Down()",0.2) end
mainScreen.drawObject("action"..side.."Up")
mainScreen.drawObject("action"..side.."Down")
else
up.state = "off"
up.clickable = false
down.state = "off"
down.clickable = false
mainScreen.drawObject("action"..side.."Up")
mainScreen.drawObject("action"..side.."Down")
end
else
obj.text = name=="none" and "No Tool" or "?"
obj.state ="off"
obj.clickable = false
mainScreen.drawObject("action"..side)
up.state = "off"
up.clickable = false
down.state = "off"
down.clickable = false
mainScreen.drawObject("action"..side.."Up")
mainScreen.drawObject("action"..side.."Down")
end
end
local function getLeftTool()
message({action="getLeftTool"})
while true do
local msg = waitForMessage()
if msg.action == "getLeftTool" then
tools.left = msg.result
return msg.result
end
end
end
local function getRightTool()
message({action="getRightTool"})
while true do
local msg = waitForMessage()
if msg.action == "getRightTool" then
tools.right = msg.result
return msg.result
end
end
end
local function detectTools()
showToolName(getRightTool(),"Right")
showToolName(getLeftTool(),"Left")
end
--=== Program ===--
if not pocket then
printError("This program requires a pocket computer!")
return
elseif args[1] == "help" then
print("ControlMe")
print("By HPWebcamAble")
print("")
print("Use this program to remotly control your turtle!")
print("Start this program on your pockect computer and the corresponding program on a turtle and control away!")
end
do
local modemSide = getModem()
if modemSide then
rednet.open(modemSide)
else
printError("This program requires a wireless modem")
return
end
end
local continue = true
while continue do
color(colors.white,colors.black) term.clear()
printC("Enter your Turtle's ID:",5)
term.setCursorPos(math.floor(w/2)-2,6)
local input = tonumber(read())
if input then
color(colors.white,colors.black) term.clear()
printC("Connecting to",5)
printC("turtle ID "..input,6)
printC("(*)",8)
local state = 1
turtleID = input
message({action="connect",id=input})
local timer = os.startTimer(1)
while true do
local event = {os.pullEventRaw()}
if event[1] == "terminate" then
term.clear() term.setCursorPos(1,1) print("Program terminated")
return
elseif event[1] == "rednet_message" and checkMessage(event,true) then
if event[3] == "connected" then
continue = false
break
end
elseif event[1] == "timer" and event[2] == timer then
state = (state == 4 and 1 or state+1)
term.clearLine() printC(string.rep("(",state).."*"..string.rep(")",state),8)
message({action="connect",id=input})
timer = os.startTimer(1)
end
end
end
end
local function heartbeat()
message("ping")
local timer = os.startTimer(2)
while true do
local event = {os.pullEvent()}
if event[1] == "rednet_message" then
if checkMessage(event,true) and event[3] == "pong" then
sleep(3)
message("ping")
timer = os.startTimer(2)
end
elseif event[1] == "timer" and event[2] == timer then
color(colors.white,colors.black) term.setCursorPos(1,1) term.clear() print("Lost contact with turtle!")
error("FORCEQUIT")
end
end
end
local function main()
drawMainScreen()
detectTools()
while true do
local event = {mainScreen.handleEvents()}
if event[1] == "rednet_message" and checkMessage(event) then
local msg = event[3]
if msg.action == "ping" then
message("pong")
end
elseif event[1] == "key" then
if event[2] == keys.up or event[2] == keys.w then
forward()
elseif event[2] == keys.down or event[2] == keys.s then
back()
elseif event[2] == keys.right or event[2] == keys.d then
turnRight()
elseif event[2] == keys.left or event[2] == keys.a then
turnLeft()
elseif event[2] == keys.space then
up()
elseif event[2] == keys.leftShift then
down()
elseif event[2] == keys.q then
end
elseif event[1] == "object" then
end
end
end
local function run()
parallel.waitForAny(main,heartbeat)
end
local state,err = pcall(run)
if err then
if not err:find("Terminated") and not err:find("FORCEQUIT") then
color(colors.white,colors.black)
term.clear()
printC("An error occured:",1)
term.setCursorPos(1,3)
print(err)
elseif not err:find("FORCEQUIT") then
color(colors.white,colors.black)
term.clear()
term.setCursorPos(1,1)
end
else
color(colors.white,colors.black)
term.clear()
term.setCursorPos(1,1)
end