-- Touch-Enabled Command Center for Pocket Computer (FIXED) -- Monitor and control autonomous mining turtles local Channels = require('platform.channels') local WebBridge = require('platform.webbridge') local CHANNEL_SEND = Channels.get('remoteturtle.command') local CHANNEL_RECEIVE = Channels.get('remoteturtle.response') local STATUS_CHANNEL = Channels.get('remoteturtle.status') local modem = peripheral.find("modem") if not modem then error("No wireless modem found!") end if pocket then pocket.equipBack() modem = peripheral.find("modem") end WebBridge.openChannels(modem, { 'remoteturtle.response', 'remoteturtle.status', }) local w, h = term.getSize() -- Tracked turtles local turtles = {} local selectedTurtle = nil local viewMode = "overview" -- overview, detail, manual, modes -- Button system local buttons = {} local function clearButtons() buttons = {} end local function addButton(x, y, width, height, label, action, color) table.insert(buttons, { x = x, y = y, width = width, height = height, label = label, action = action, color = color or colors.gray }) end local function drawButton(btn, highlight) term.setCursorPos(btn.x, btn.y) if highlight then term.setBackgroundColor(colors.white) term.setTextColor(colors.black) else term.setBackgroundColor(btn.color) term.setTextColor(colors.white) end local text = btn.label local padding = math.floor((btn.width - #text) / 2) for dy = 0, btn.height - 1 do term.setCursorPos(btn.x, btn.y + dy) if dy == math.floor(btn.height / 2) then term.write(string.rep(" ", padding) .. text .. string.rep(" ", btn.width - padding - #text)) else term.write(string.rep(" ", btn.width)) end end term.setBackgroundColor(colors.black) term.setTextColor(colors.white) end local function checkButton(x, y) for _, btn in ipairs(buttons) do if x >= btn.x and x < btn.x + btn.width and y >= btn.y and y < btn.y + btn.height then return btn end end return nil end -- Send command to turtle local function sendCommand(turtleID, command, param) modem.transmit(CHANNEL_SEND, CHANNEL_RECEIVE, { command = command, param = param, target = turtleID }) end -- Send state change command to turtle (new protocol) local function sendStateCommand(turtleID, stateName, stateData) modem.transmit(CHANNEL_SEND, CHANNEL_RECEIVE, { type = "state_change", state = stateName, data = stateData or {}, target = turtleID }) end -- Helper function to format fuel display local function formatFuel(fuel) if not fuel then return "?" elseif fuel == "unlimited" then return "INF" else return tostring(fuel) end end -- Draw UI modes local function drawOverview() clearButtons() term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1, 1) term.setTextColor(colors.yellow) print("=MINING CMD CENTER=") term.setTextColor(colors.white) local startY = 3 if #turtles == 0 then term.setCursorPos(1, startY) print("No turtles online") print("Waiting...") else for i, turtle in ipairs(turtles) do if i > 3 then break end -- Max 3 turtles on screen local y = startY + (i - 1) * 4 local selected = (selectedTurtle == i) -- Turtle info box term.setCursorPos(1, y) term.setTextColor(selected and colors.lime or colors.white) print(string.format("T-%d [%s]", turtle.turtleID or 0, turtle.state or turtle.mode or "idle")) if turtle.position then print(string.format(" %d,%d,%d", turtle.position.x or 0, turtle.position.y or 0, turtle.position.z or 0)) else print(" No GPS") end print(string.format(" F:%s I:%d", formatFuel(turtle.fuel), turtle.inventoryCount or 0)) -- Select button addButton(20, y, 6, 2, "SEL", function() selectedTurtle = i viewMode = "detail" end, selected and colors.lime or colors.blue) drawButton(buttons[#buttons]) end end -- Bottom buttons local btnY = h - 3 addButton(1, btnY, 8, 2, "EXPLORE", function() if selectedTurtle and turtles[selectedTurtle] then sendCommand(turtles[selectedTurtle].turtleID, "explore") end end, colors.green) addButton(10, btnY, 8, 2, "HOME", function() if selectedTurtle and turtles[selectedTurtle] then sendCommand(turtles[selectedTurtle].turtleID, "returnHome") end end, colors.orange) addButton(19, btnY, 7, 2, "STOP", function() if selectedTurtle and turtles[selectedTurtle] then sendCommand(turtles[selectedTurtle].turtleID, "stop") end end, colors.red) for _, btn in ipairs(buttons) do drawButton(btn) end term.setTextColor(colors.white) end local function drawDetail() if not selectedTurtle or not turtles[selectedTurtle] then viewMode = "overview" drawOverview() return end clearButtons() local turtle = turtles[selectedTurtle] term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1, 1) term.setTextColor(colors.yellow) print("=TURTLE " .. (turtle.turtleID or "?") .. "=") term.setTextColor(colors.white) print("") print("State: " .. (turtle.state or turtle.mode or "idle")) print("Fuel: " .. formatFuel(turtle.fuel)) if turtle.position then print(string.format("Pos: %d,%d,%d", turtle.position.x or 0, turtle.position.y or 0, turtle.position.z or 0)) else print("Pos: No GPS") end if turtle.homePosition and turtle.position then local dist = math.abs((turtle.position.x or 0) - (turtle.homePosition.x or 0)) + math.abs((turtle.position.y or 0) - (turtle.homePosition.y or 0)) + math.abs((turtle.position.z or 0) - (turtle.homePosition.z or 0)) print("Home: " .. dist .. " blocks") elseif turtle.homePosition then print("Home: Set") else print("Home: Not set") end print("") print("Inventory:") if turtle.inventory and #turtle.inventory > 0 then for i, item in ipairs(turtle.inventory) do if i <= 4 then local name = item.name:match("minecraft:(.+)") or item.name if #name > 18 then name = name:sub(1, 15) .. "..." end print(string.format("%d:%s x%d", item.slot or 0, name, item.count or 0)) end end else print(" Empty") end -- Action buttons (row 1: explore/home/stop) local btnY = h - 10 addButton(1, btnY, 8, 2, "EXPLORE", function() sendCommand(turtle.turtleID, "explore") end, colors.green) addButton(10, btnY, 8, 2, "HOME", function() sendCommand(turtle.turtleID, "returnHome") end, colors.orange) addButton(19, btnY, 7, 2, "STOP", function() sendCommand(turtle.turtleID, "stop") end, colors.red) -- Row 2: manual/modes/setHome btnY = h - 7 addButton(1, btnY, 8, 2, "MANUAL", function() viewMode = "manual" sendCommand(turtle.turtleID, "manual") end, colors.purple) addButton(10, btnY, 8, 2, "MODES", function() viewMode = "modes" end, colors.cyan) addButton(19, btnY, 7, 2, "HOME*", function() sendCommand(turtle.turtleID, "setHome") end, colors.blue) -- Row 3: equip/rename btnY = h - 4 addButton(1, btnY, 8, 2, "EQUIP L", function() -- Send eval to equip left modem.transmit(CHANNEL_SEND, CHANNEL_RECEIVE, { type = "eval", uuid = tostring(math.random(100000, 999999)), code = "return turtle.equipLeft()", target = turtle.turtleID }) end, colors.purple) addButton(10, btnY, 8, 2, "EQUIP R", function() modem.transmit(CHANNEL_SEND, CHANNEL_RECEIVE, { type = "eval", uuid = tostring(math.random(100000, 999999)), code = "return turtle.equipRight()", target = turtle.turtleID }) end, colors.purple) addButton(19, btnY, 7, 2, "RENAME", function() term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1, 1) term.setTextColor(colors.yellow) print("Enter new name:") term.setTextColor(colors.white) local name = read() if name and #name > 0 then modem.transmit(CHANNEL_SEND, CHANNEL_RECEIVE, { type = "rename", name = name, target = turtle.turtleID }) end draw() end, colors.lightBlue) addButton(1, h - 1, 12, 2, "< BACK", function() viewMode = "overview" end, colors.gray) for _, btn in ipairs(buttons) do drawButton(btn) end term.setTextColor(colors.white) end local function drawManual() if not selectedTurtle or not turtles[selectedTurtle] then viewMode = "overview" return end clearButtons() local turtle = turtles[selectedTurtle] term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1, 1) term.setTextColor(colors.red) print("=MANUAL CONTROL=") term.setTextColor(colors.white) print(string.format("T-%d Fuel:%s", turtle.turtleID or 0, formatFuel(turtle.fuel))) -- Movement buttons local centerX = 6 local centerY = 5 -- Forward addButton(centerX, centerY, 3, 2, "W", function() sendCommand(turtle.turtleID, "forward") end, colors.blue) -- Left addButton(centerX - 4, centerY + 2, 3, 2, "A", function() sendCommand(turtle.turtleID, "turnLeft") end, colors.blue) -- Back addButton(centerX, centerY + 2, 3, 2, "S", function() sendCommand(turtle.turtleID, "back") end, colors.blue) -- Right addButton(centerX + 4, centerY + 2, 3, 2, "D", function() sendCommand(turtle.turtleID, "turnRight") end, colors.blue) -- Up/Down addButton(centerX + 9, centerY, 4, 2, "UP", function() sendCommand(turtle.turtleID, "up") end, colors.cyan) addButton(centerX + 9, centerY + 2, 4, 2, "DN", function() sendCommand(turtle.turtleID, "down") end, colors.cyan) -- Action buttons local actY = centerY + 5 addButton(1, actY, 6, 2, "DIG", function() sendCommand(turtle.turtleID, "dig") end, colors.orange) addButton(8, actY, 6, 2, "PLACE", function() sendCommand(turtle.turtleID, "place") end, colors.green) addButton(15, actY, 6, 2, "DIGUP", function() sendCommand(turtle.turtleID, "digUp") end, colors.orange) addButton(22, actY, 5, 2, "DIGD", function() sendCommand(turtle.turtleID, "digDown") end, colors.orange) -- Bottom buttons addButton(1, h - 3, 8, 2, "HOME", function() sendCommand(turtle.turtleID, "returnHome") end, colors.orange) addButton(10, h - 3, 8, 2, "REFUEL", function() sendCommand(turtle.turtleID, "refuel") end, colors.lime) addButton(19, h - 3, 7, 2, "SORT", function() modem.transmit(CHANNEL_SEND, CHANNEL_RECEIVE, { type = "eval", uuid = tostring(math.random(100000, 999999)), code = [[ local moved = 0 for slot = 1, 16 do local item = turtle.getItemDetail(slot) if item then for target = 1, slot - 1 do local ti = turtle.getItemDetail(target) if not ti then turtle.select(slot) turtle.transferTo(target) moved = moved + 1 break elseif ti.name == item.name and ti.count < 64 then turtle.select(slot) turtle.transferTo(target) moved = moved + 1 if turtle.getItemCount(slot) == 0 then break end end end end end turtle.select(1) return moved ]], target = turtle.turtleID }) end, colors.cyan) addButton(1, h, 12, 1, "< BACK", function() viewMode = "detail" end, colors.gray) addButton(14, h, 13, 1, "AUTO MODE", function() sendCommand(turtle.turtleID, "explore") viewMode = "detail" end, colors.purple) for _, btn in ipairs(buttons) do drawButton(btn) end term.setTextColor(colors.white) end local function drawModes() if not selectedTurtle or not turtles[selectedTurtle] then viewMode = "overview" return end clearButtons() local turtle = turtles[selectedTurtle] term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1, 1) term.setTextColor(colors.cyan) print("=STATE MACHINE=") term.setTextColor(colors.white) print(string.format("T-%d [%s]", turtle.turtleID or 0, turtle.state or turtle.mode or "idle")) -- State buttons local btnY = 4 local btnW = 12 addButton(1, btnY, btnW, 2, "IDLE", function() sendStateCommand(turtle.turtleID, "idle") sendCommand(turtle.turtleID, "stop") end, colors.gray) addButton(14, btnY, btnW, 2, "EXPLORE", function() sendStateCommand(turtle.turtleID, "exploring") sendCommand(turtle.turtleID, "explore") end, colors.green) btnY = btnY + 3 addButton(1, btnY, btnW, 2, "MINE", function() sendStateCommand(turtle.turtleID, "mining") sendCommand(turtle.turtleID, "explore") end, colors.orange) addButton(14, btnY, btnW, 2, "FARM", function() sendStateCommand(turtle.turtleID, "farming") end, colors.lime) btnY = btnY + 3 addButton(1, btnY, btnW, 2, "GO HOME", function() sendStateCommand(turtle.turtleID, "goHome") sendCommand(turtle.turtleID, "returnHome") end, colors.yellow) addButton(14, btnY, btnW, 2, "REFUEL", function() sendStateCommand(turtle.turtleID, "refueling") sendCommand(turtle.turtleID, "refuel") end, colors.red) btnY = btnY + 3 addButton(1, btnY, btnW, 2, "DUMP INV", function() sendStateCommand(turtle.turtleID, "dumpInventory") end, colors.brown) addButton(14, btnY, btnW, 2, "MOVE TO", function() -- Could prompt for coordinates, for now just sends moving state sendStateCommand(turtle.turtleID, "moving") end, colors.lightBlue) btnY = btnY + 3 addButton(1, btnY, btnW, 2, "SCAN", function() sendStateCommand(turtle.turtleID, "scan") end, colors.purple) addButton(14, btnY, btnW, 2, "EXTRACT", function() sendStateCommand(turtle.turtleID, "extraction") end, colors.magenta) btnY = btnY + 3 addButton(1, btnY, btnW, 2, "BUILD", function() sendStateCommand(turtle.turtleID, "building") end, colors.lightBlue) addButton(14, btnY, btnW, 2, "AUTOCRAFT", function() sendStateCommand(turtle.turtleID, "autocraft") end, colors.pink) -- Back button addButton(1, h - 1, 12, 2, "< BACK", function() viewMode = "detail" end, colors.gray) for _, btn in ipairs(buttons) do drawButton(btn) end term.setTextColor(colors.white) end local function draw() if viewMode == "overview" then drawOverview() elseif viewMode == "detail" then drawDetail() elseif viewMode == "manual" then drawManual() elseif viewMode == "modes" then drawModes() end end -- Handle keyboard input (still works alongside touch) local function handleKey(key) if viewMode == "manual" then local turtle = turtles[selectedTurtle] if not turtle then return end local cmd = nil if key == keys.w then cmd = "forward" elseif key == keys.s then cmd = "back" elseif key == keys.a then cmd = "turnLeft" elseif key == keys.d then cmd = "turnRight" elseif key == keys.space then cmd = "up" elseif key == keys.leftShift or key == keys.rightShift then cmd = "down" elseif key == keys.e then cmd = "dig" elseif key == keys.q then cmd = "place" end if cmd then sendCommand(turtle.turtleID, cmd) end elseif viewMode == "overview" then if key >= keys.one and key <= keys.nine then local index = key - keys.one + 1 if turtles[index] then selectedTurtle = index viewMode = "detail" draw() end end end end -- Handle touch local function handleTouch(x, y) local btn = checkButton(x, y) if btn and btn.action then -- Visual feedback drawButton(btn, true) sleep(0.1) drawButton(btn, false) -- Execute action btn.action() draw() end end -- Main loop print("Initializing...") sleep(0.5) draw() parallel.waitForAny( function() -- Touch/click handler while true do local event, p1, p2, p3 = os.pullEvent() if event == "mouse_click" or event == "monitor_touch" then handleTouch(p2, p3) end end end, function() -- Keyboard handler while true do local event, key = os.pullEvent("key") handleKey(key) end end, function() -- Status receiver -- Uses Channels.match() for dual-mode safety: accepts status on -- both legacy (102) and target (4212) channels during migration. while true do local event, side, channel, replyChannel, message = os.pullEvent("modem_message") if Channels.match('remoteturtle.status', channel) and type(message) == "table" and message.type == "status" then -- Update or add turtle local found = false for i, t in ipairs(turtles) do if t.turtleID == message.turtleID then -- Preserve state if not in message if not message.state then message.state = t.state or message.mode or "idle" end turtles[i] = message found = true break end end if not found then if not message.state then message.state = message.mode or "idle" end table.insert(turtles, message) if not selectedTurtle then selectedTurtle = 1 end end draw() elseif Channels.match('remoteturtle.response', channel) and type(message) == "table" then -- State change confirmation or other response if message.type == "state_changed" and message.turtleID then for i, t in ipairs(turtles) do if t.turtleID == message.turtleID then turtles[i].state = message.state break end end end draw() end end end, function() -- Refresh display while true do sleep(2) draw() end end )