-- ArcTurtleWatching PROGRAM -- This program is intended to be used with my turtle programs (vertical mining and chunk loading) -- The goal is to show the status of your turtles on a monitor and to send to players chat messages when a turtle has an error or has finished his work -- The program uses multiple peripherals from Advanced Peripherals -- - The chat box is used to send you chat messages -- - The environment detector is used to show the dimension the turtle is in on the monitor -- - The player detector is used to detect player connection and send them awaiting reports -- You can connect every peripheral as you want, the program will detect them where they are -- Every peripheral (except the wireless modem) can be absent, the program will ignore their specific uses -- You can have up to 17 players to send message to local ArcConst = require("ArcConstants") local ArcTerm = require("ArcTerm") local ArcMonitor = require("ArcMonitor") local ArcUtilities = require("ArcUtilities") -- GLOBAL VARIABLES -- Peripherals local gModem = nil -- Wrapped modem local gMonitor = nil -- Wrapped monitor local gChatBox = nil -- Wrapped chat box local gEnvDetector = nil -- Wrapped environment detector local gPlayerDetector = nil -- Wrapped player detector -- Miscellaneous local gsReportProtocol = "ATW" -- Report protocol code to receive reports local gtabTurtleData = {} -- Contains all turtles data local gnShowedTurtleIndex = 0 -- Index of the actual turtle showed on monitor local gtabsPlayers = {} -- List of players to send reports to local gsPlayersFileName = "Players.atw" -- Registered players file name local gtabsFacing = {"north","east","south","west","unknown"} -- FUNCTIONS local function GetTurtleIndex(pnTurtleId) for i=1,#gtabTurtleData,1 do if gtabTurtleData[i][ArcConst.TDS_ID] == pnTurtleId then return i end end return nil end local function GetPlayerIndex(psPlayer) for i=1,#gtabsPlayers,1 do if gtabsPlayers[i] == psPlayer then return i end end return nil end local function SavePlayers() local File = fs.open(gsPlayersFileName,"w+") for i=1,#gtabsPlayers,1 do File.writeLine(gtabsPlayers[i]) end File.close() end local function LoadPlayers() local File = nil local sLine = nil if not fs.exists(gsPlayersFileName) then return false end File = fs.open(gsPlayersFileName,"r") sLine = File.readLine() while sLine ~= nil do table.insert(gtabsPlayers,sLine) sLine = File.readLine() end File.close() end local function RefreshMonitor() local sDimension = nil if gMonitor == nil then return false end if gEnvDetector ~= nil then sDimension = ArcUtilities.StringExtract(gEnvDetector.getDimension(),2,":") else sDimension = "unknown" end ArcMonitor.Reset() ArcMonitor.Write(1,1,"<========== TURTLE WATCHING ==========>") if gnShowedTurtleIndex == 0 then ArcMonitor.Write(15,9,"NO TURTLE") ArcMonitor.Write(15,12,"DETECTED") return true end ArcMonitor.Write(1,3,("Turtle type : %s"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_TYPE])) ArcMonitor.Write(1,4,("Dimension : %s"):format(sDimension)) if gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_LOCATION] == 1 then ArcMonitor.Write(1,5,("Position length : %d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSLX])) ArcMonitor.Write(1,6,("Position width : %d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSWY])) ArcMonitor.Write(1,7,("Position depth : %d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSDZ])) ArcMonitor.Write(1,8,("Orientation : %d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSO])) else ArcMonitor.Write(1,5,("Position x : %d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSLX])) ArcMonitor.Write(1,6,("Position y : %d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSWY])) ArcMonitor.Write(1,7,("Position z : %d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSDZ])) ArcMonitor.Write(1,8,("Facing : %s"):format(gtabsFacing[gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_POSO]])) end if gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_TYPE] == ArcConst.TT_VERTICALMINING then ArcMonitor.Write(1,10,("Mine shaft : %d/%d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_ADVANCEMENT],gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_GOAL])) else ArcMonitor.Write(1,10,("Checkpoint : %d/%d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_ADVANCEMENT],gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_GOAL])) end ArcMonitor.Write(1,11,("Fuel level : %d/%d"):format(gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_FUELLEVEL],gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_FUELLIMIT])) ArcMonitor.Write(1,13,"Current Status :") ArcMonitor.Write(1,14,gtabTurtleData[gnShowedTurtleIndex][ArcConst.TDS_STATUS]) ArcMonitor.Write(20-string.len(gnShowedTurtleIndex),17,("%d/%d"):format(gnShowedTurtleIndex,#gtabTurtleData)) ArcMonitor.CreateButton(2,16,10,3,colors.lightGray) ArcMonitor.Write(5,17,"Prev",colors.black,colors.lightGray) ArcMonitor.CreateButton(29,16,10,3,colors.lightGray) ArcMonitor.Write(32,17,"Next",colors.black,colors.lightGray) end local function GetPeripheralStatus(pPeripheral) if pPeripheral == nil then return "not found" else return "running" end end local function Menu() local nKey = nil local bExit = nil local sPlayer = nil local nPlayerIndex = nil while true do while true do ArcTerm.Reset() ArcTerm.Write(1,1,"<================ TURTLE WATCHING ================>") ArcTerm.Write(1,3,"-- Peripherals status --") ArcTerm.Write(1,4,("Modem : %s"):format(GetPeripheralStatus(gModem))) ArcTerm.Write(1,5,("Monitor : %s"):format(GetPeripheralStatus(gMonitor))) ArcTerm.Write(1,6,("Chat box : %s"):format(GetPeripheralStatus(gChatBox))) ArcTerm.Write(1,7,("Environment detector : %s"):format(GetPeripheralStatus(gEnvDetector))) ArcTerm.Write(1,8,("Player detector : %s"):format(GetPeripheralStatus(gPlayerDetector))) ArcTerm.Write(1,10,"Protocol code : ") if gsReportProtocol == nil or gsReportProtocol == "" then gsReportProtocol = ArcTerm.Read(24,10);break else ArcTerm.Write(24,10,gsReportProtocol) end ArcTerm.Write(1,12,"- 1 | Manage players") ArcTerm.Write(1,13,"- 2 | Change protocol code") ArcTerm.Write(1,14,"- 3 | Reboot") ArcTerm.Write(1,14,"- 4 | Update") ArcTerm.Write(1,15,"- 5 | Shutdown") bExit = false nKey = ArcUtilities.KeyToNumber(ArcTerm.ReadKey()) if nKey == 1 then repeat ArcTerm.Reset() while true do ArcTerm.Write(1,1,"<==================== PLAYERS ====================>") for i=1,#gtabsPlayers,1 do ArcTerm.Write(1,1+i,gtabsPlayers[i]) end ArcTerm.Write(1,19,"1 | Add player - 2 | Remove player - 3 | Exit") nKey = ArcUtilities.KeyToNumber(ArcTerm.ReadKey()) if nKey == 1 then if #gtabsPlayers >= 17 then ArcTerm.Write(1,19,ArcUtilities.Complete("Error : too many players"," ",51,"R",false)) os.sleep(2) break end ArcTerm.Write(1,19,ArcUtilities.Complete("Player name : "," ",51,"R",false)) sPlayer = ArcTerm.Read(15,19) if sPlayer == nil or sPlayer == "" then break end nPlayerIndex = GetPlayerIndex(sPlayer) if nPlayerIndex ~= nil then ArcTerm.Write(1,19,ArcUtilities.Complete("Error : player already registered"," ",51,"R",false)) os.sleep(2) break end table.insert(gtabsPlayers,sPlayer) SavePlayers() elseif nKey == 2 then if #gtabsPlayers == 0 then ArcTerm.Write(1,19,ArcUtilities.Complete("Error : no player registered"," ",51,"R",false)) os.sleep(2) break end ArcTerm.Write(1,19,ArcUtilities.Complete("Player name : "," ",51,"R",false)) sPlayer = ArcTerm.Read(15,19) if sPlayer == nil or sPlayer == "" then break end nPlayerIndex = GetPlayerIndex(sPlayer) if nPlayerIndex == nil then ArcTerm.Write(1,19,ArcUtilities.Complete("Error : player not registered"," ",51,"R",false)) os.sleep(2) break end table.remove(gtabsPlayers,nPlayerIndex) SavePlayers() elseif nKey == 3 then bExit = true end break end until bExit elseif nKey == 2 then gsReportProtocol = nil elseif nKey == 3 then os.reboot() elseif nKey == 4 then os.reboot() elseif nKey == 5 then os.shutdown() end end end end local function SendMessageToPlayer(pTurtleData,psPlayer) if gChatBox == nil then return false end gChatBox.sendMessageToPlayer(("Turtle #%d status update : %s"):format(pTurtleData[ArcConst.TDS_ID],string.lower(pTurtleData[ArcConst.TDS_STATUS])),psPlayer,gsReportProtocol.." report") end local function TurtleListen() local nSenderId = nil local sMessage = nil local sProtocol = nil local TurtleData = nil local nTurtleIndex = nil local bUpdate = nil if gModem == nil then return false end while true do bUpdate = false nSenderId,sMessage,sProtocol = rednet.receive(gsReportProtocol) TurtleData = textutils.unserialise(sMessage.sTurtleData) nTurtleIndex = GetTurtleIndex(TurtleData[ArcConst.TDS_ID]) if nTurtleIndex == nil then if TurtleData[ArcConst.TDS_STATUSTYPE] ~= ArcConst.TST_SHUTDOWN then bUpdate = true table.insert(gtabTurtleData,TurtleData) if #gtabTurtleData == 1 then gnShowedTurtleIndex = 1 end RefreshMonitor() end else if TurtleData[ArcConst.TDS_STATUSTYPE] == ArcConst.TST_SHUTDOWN then table.remove(gtabTurtleData,nTurtleIndex) if gnShowedTurtleIndex > #gtabTurtleData then gnShowedTurtleIndex = #gtabTurtleData end RefreshMonitor() else for i=1,#TurtleData,1 do if gtabTurtleData[nTurtleIndex][i] ~= TurtleData[i] then bUpdate = true end end if bUpdate then for i=1,#TurtleData,1 do gtabTurtleData[nTurtleIndex][i] = TurtleData[i] end if gnShowedTurtleIndex == nTurtleIndex then RefreshMonitor() end end end end if bUpdate and TurtleData[ArcConst.TDS_STATUSTYPE] == ArcConst.TST_NEEDPLAYER then for i=1,#gtabsPlayers,1 do SendMessageToPlayer(TurtleData,gtabsPlayers[i]) end end end end local function MonitorTouch() local sEvent = nil local sSide = nil local nX = nil local nY = nil local nButtonIndex = nil if gMonitor == nil then return false end while true do while true do sEvent,sSide,nX,nY = os.pullEvent("monitor_touch") if #gtabTurtleData <= 1 then break end nButtonIndex = ArcMonitor.GetButtonIndex(nX,nY) if nButtonIndex == nil then break end if nButtonIndex == 1 then gnShowedTurtleIndex = gnShowedTurtleIndex-1 if gnShowedTurtleIndex <= 0 then gnShowedTurtleIndex = #gtabTurtleData end elseif nButtonIndex == 2 then gnShowedTurtleIndex = gnShowedTurtleIndex+1 if gnShowedTurtleIndex > #gtabTurtleData then gnShowedTurtleIndex = 1 end end RefreshMonitor() end end end local function DetectPlayersConnexion() local sEvent = nil local sPlayer = nil local sDimension = nil if gPlayerDetector == nil or gChatBox == nil then return false end while true do sEvent,sPlayer,sDimension = os.pullEvent("playerJoin") for i=1,#gtabsPlayers[i],1 do if sPlayer == #gtabsPlayers[i] then for j=1,#gtabTurtleData,1 do if gtabTurtleData[j][ArcConst.TDS_STATUSTYPE] == ArcConst.TST_NEEDPLAYER then SendMessageToPlayer(gtabTurtleData[j],sPlayer) end end end end end end local function CheckPeripherals() local tabPeripherals = nil local sPeripheralType1 = nil local sPeripheralType2 = nil tabPeripherals = peripheral.getNames() for i=1,#tabPeripherals,1 do sPeripheralType1,sPeripheralType2 = peripheral.getType(tabPeripherals[i]) if sPeripheralType1 == "modem" and sPeripheralType2 == nil then gModem = tabPeripherals[i] rednet.open(gModem) elseif sPeripheralType1 == "monitor" then gMonitor = peripheral.wrap(tabPeripherals[i]) elseif sPeripheralType1 == "chat_box" then gChatBox = peripheral.wrap(tabPeripherals[i]) elseif sPeripheralType1 == "environment_detector" then gEnvDetector = peripheral.wrap(tabPeripherals[i]) elseif sPeripheralType1 == "player_detector" then gPlayerDetector = peripheral.wrap(tabPeripherals[i]) end end end CheckPeripherals() ArcMonitor.SetMonitor(gMonitor) RefreshMonitor() LoadPlayers() os.sleep(0.1) parallel.waitForAll(Menu,TurtleListen,MonitorTouch,DetectPlayersConnexion)