ComputerCraft Archive

ControlMe - Remote control for your turtle!

turtle mining unknown forum

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

turtleminingforumturtle-programs

Source

View Original Source

Code 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