Posted 12 January 2014 - 03:11 AM
I wrote this portal computer / portal turtle program after viewing ArmitageShanks You Tube Video and addressing many of the issues he was struggling with. The buttons automatically configure on advanced monitor panels which are 4 wide and 3 high. I use routers with machine Filters, Auto Ejectors and SpeedBoosts installed. The users on my servers love the new portal system.
The portal computer code can be downloaded at: http://pastebin.com/amCuLiLa
The portal dialer turtle code can be downloaded at: http://pastebin.com/aysQLJG7
This was one of my first attempts at having computers/turtles announce themselves to each other and somewhat auto-configure. in addition, this was definitely my first attempt at using tables to hold both objects (like monitors) as well as data.
If you use this, you will need to modify the code to reflect your book inventory/titles as well as to place the labels of your monitors in the code.
If I rewrite this, I plan on using coroutines to make the handshaking between turtles and the portal computer work more gracefully. The portal computer will display a lot of troubleshooting information at present. Someday, I may pretty it up.
Hope it is helpful. Enjoy.
[media]http://www.youtube.com/watch?v=36eRfsDaUdo[/media]
Here are screenshots of my server's Portal Room.
Portal Room
Turtle and Router feeding Book Receptacle
Portal Computer Screenshot
The portal computer code can be downloaded at: http://pastebin.com/amCuLiLa
Portal Dialer Computer Code
-- Portal Computer v 2.2 (inspired by Armitige Shanks You Tube video of same)
-- by Mike Simpkins December 2013 (Creative Commons)
-- Paired with Portal Turtle (http://pastebin.com/aysQLJG7)
wirelessModemSide="bottom"
showDebug=false
hasDrawBridge=1
drawBridgeColor=colors.orange
drawBridgeOutput="top"
startingRow=5
numberRows=4
numberColumns=4
linesPerRow=4
columnWidth=10
borderColor=colors.cyan
buttonBackgroundColor=colors.lightBlue
buttonTextColor=colors.black
buttonSelectedBackground=colors.lime
buttonSelectedTextColor=colors.white
buttonDisabledBackgroundColor=colors.lightGray
buttonDisabledTextColor=colors.gray
portalMessageBackground=colors.yellow
rednet.open(wirelessModemSide)
local screen = 1
local numberOfPages = 3
local pages =
{
--center
[1]={Monitor=peripheral.wrap("monitor_13"),Side="monitor_13",Title="PLAYER LOCATIONS",Buttons=
{
[1]={Label1 ="Oatmeal",Label2=" Defender",Label3="",Enabled=true},
[2]={Label1 ="",Label2="Surferpup",Label3="",Enabled=true},
[3]={Label1 = "Bremon",Label2="&",Label3="Kirra",Enabled=false},
[4]={Label1 ="MoNKi",Label2="Di",Label3="RuFFi",Enabled=false},
[5]={Label1 = "Telephone",Label2="Guy",Label3="",Enabled=false},
[6]={Label1 = "",Label2=" MacBoyJr",Label3="",Enabled=true},
[7]={Label1 = "Enderman",Label2="209",Label3="",Enabled=false},
[8]={Label1 = "Korbynx",Label2="&",Label3="Joeltine",Enabled=true},
[9]={Label1 ="",Label2="Gh0stRAT",Label3="",Enabled=false},
[10]={Label1 ="",Label2="",Label3="",Enabled=false},
[11]={Label1 ="",Label2="",Label3="",Enabled=false},
[12]={Label1 ="",Label2="",Label3="",Enabled=true},
[13]={Label1 = "",Label2="",Label3="",Enabled=false},
[14]={Label1 = "",Label2="",Label3="",Enabled=true},
[15]={Label1 = "",Label2="",Label3="",Enabled=true},
[16]={Label1 = "",Label2="",Label3="",Enabled=true}
}},
--left
[2]={Monitor=peripheral.wrap("monitor_12"),Side="monitor_12",Title="WORLD PLACES",Buttons=
{
[1]={Label1 = "Portal",Label2="Room",Label3="",Enabled=false},
[2]={Label1 ="Lovely",Label2="Portoa",Label3="",Enabled=false},
[3]={Label1 ="New",Label2="Mining",Label3="World",Enabled=true},
[4]={Label1 ="Old",Label2="Mining",Label3="World",Enabled=true},
[5]={Label1 ="The",Label2="Nether",Label3="",Enabled=false},
[6]={Label1 ="",Label2="THE END",Label3="",Enabled=false},
[7]={Label1 ="Twilight",Label2="Forest",Label3="",Enabled=true},
[8]={Label1 ="Promised",Label2="Land",Label3="",Enabled=false},
[9]={Label1="Original",Label2="Spawn",Label3="",Enabled=false},
[10]={Label1 ="",Label2="",Label3="",Enabled=false},
[11]={Label1 ="",Label2="",Label3="",Enabled=false},
[12]={Label1 ="",Label2="",Label3="",Enabled=false},
[13]={Label1 ="",Label2="",Label3="",Enabled=true},
[14]={Label1 ="",Label2="",Label3="",Enabled=false},
[15]={Label1 ="",Label2="",Label3="",Enabled=false},
[16]={Label1 ="",Label2="",Label3="",Enabled=true}
}},
--right
[3]={Monitor=peripheral.wrap("monitor_10"),Side="monitor_10",Title="RESTRICTED LOCATIONS",Buttons=
{
[1]={Label1 ="Portal",Label2="Back",Label3="Room",Enabled=false},
[2]={Label1 ="Portal",Label2="Emergency",Label3="Exit",Enabled=false},
[3]={Label1 ="Surferpup",Label2="Machine",Label3="Room",Enabled=true},
[4]={Label1 ="",Label2="",Label3="",Enabled=true},
[5]={Label1 ="Nexus",Label2="Area 51",Label3="",Enabled=false},
[6]={Label1 ="Nexus",Label2="Storage",Label3="Tanks",Enabled=true},
[7]={Label1 ="",Label2="",Label3="",Enabled=true},
[8]={Label1 ="",Label2="",Label3="",Enabled=true},
[9]={Label1 ="Surferpup",Label2="OldWorld",Label3="House",Enabled=true},
[10]={Label1 = "Oatmeal",Label2="OldWorld",Label3="Palace",Enabled=false},
[11]={Label1 ="Old World",Label2="Spawn",Label3="",Enabled=false},
[12]={Label1 ="",Label2="",Label3="",Enabled=false},
[13]={Label1 ="Bee-Topia",Label2="",Label3="",Enabled=true},
[14]={Label1 ="Ocean",Label2="Castle",Label3="",Enabled=false},
[15]={Label1 ="",Label2="",Label3="",Enabled=true},
[16]={Label1 ="",Label2="",Label3="",Enabled=true}
}}
}
local message=""
local turtles={}
function forceInit(page)
if (not rednet.isOpen(wirelessModemSide)) then rednet.Open(wirelessModemSide) end
rednet.send(turtles[page],"InitTurtle"..tostring(page))
initTurtle(page)
end
function forceAnnounce()
if (not rednet.isOpen(wirelessModemSide)) then rednet.Open(wirelessModemSide) end
portalMessage(true,"ACQUIRING DESTINATIONS",colors.orange)
--print("updatedPortalMessage")
while true do
print("Announcing...")
rednet.broadcast("ANNOUNCE")
event,sender,message,_ = os.pullEvent("rednet_message")
--print ("sender="..sender.."message="..(message or "BUBBA"))
if (string.sub(message or "BOB",1,6)=="TURTLE") then break end
sleep (1)
end
print ("...Done with Announce")
end
function initTurtle(page)
if (not rednet.isOpen(wirelessModemSide)) then rednet.Open(wirelessModemSide) end
portalMessage(true," REFRESHING PAGE "..tostring(page),colors.orange)
repeat
event,sender,message,_=os.pullEvent("rednet_message")
until message== "InitTurtle"..page
rednet.send(sender,"PROCEED"..page,true)
print("Sent Init PROCEED to Turtle"..page)
repeat
repeat
sender,message,_=rednet.receive()
until sender == turtles[page]
if ((message or "")~=("OK"..page)) then
status=(message or "NONE")
rednet.send(sender,status,true)
end
--print("repeating")
until message==("OK"..page)
print (status)
local turtleInventory = textutils.unserialize(status)
--print (""..#pages[1]..","..page)
for i=1,#pages[page].Buttons do
currentButton=pages[page].Buttons[i]
currentButton.Enabled=(turtleInventory[i]>0)
end
print("Turtle"..page.." Initialized")
end
function centerText(text,maxWidth)
text=text or ""
local leftPadding = math.floor((maxWidth-string.len(string.sub(text,1,maxWidth)))/2)
local newString=""
if leftPadding>0 then
newString= (string.rep(" ",leftPadding)..string.sub(text,1,maxWidth))
else
newString= string.sub(text,1,maxWidth)
end
newString=newString..string.rep(" ",maxWidth-string.len(newString))
return newString
end
function drawGUI(page)
page=page or 1
--Heading
--Monitor=peripheral.wrap(pages[page].Side)
pages[page].Monitor.clear()
pages[page].Monitor.setBackgroundColor(borderColor)
pages[page].Monitor.setCursorPos(9,1)
pages[page].Monitor.setBackgroundColor(colors.white)
pages[page].Monitor.setTextColor(colors.red)
pages[page].Monitor.write(centerText("",26))
pages[page].Monitor.setBackgroundColor(borderColor)
pages[page].Monitor.setCursorPos(9,2)
pages[page].Monitor.setBackgroundColor(colors.white)
pages[page].Monitor.write(centerText(pages[page].Title,26))
pages[page].Monitor.setBackgroundColor(borderColor)
pages[page].Monitor.setCursorPos(9,3)
pages[page].Monitor.setBackgroundColor(colors.white)
pages[page].Monitor.write(centerText("",26))
pages[page].Monitor.setBackgroundColor(borderColor)
for row = 1,numberRows do
currentRow=startingRow+((row-1)*linesPerRow)
for column = 1,numberColumns do
currentColumn=(column-1)*columnWidth+1
-- Button 1_1
currentButton = pages[page].Buttons[((row-1)*numberColumns)+column]
local buttonColor
if (currentButton.Enabled) then
buttonColor = buttonBackgroundColor
buttonText = buttonTextColor
else
buttonColor = buttonDisabledBackgroundColor
buttonText = buttonDisabledTextColor
end
pages[page].Monitor.setCursorPos(currentColumn,currentRow)
pages[page].Monitor.setBackgroundColor(buttonColor)
pages[page].Monitor.setTextColor(buttonTextColor)
pages[page].Monitor.write(centerText(currentButton.Label1,9))
pages[page].Monitor.setBackgroundColor(borderColor)
pages[page].Monitor.setCursorPos(currentColumn,currentRow+1)
pages[page].Monitor.setBackgroundColor(buttonColor)
pages[page].Monitor.setTextColor(buttonTextColor)
pages[page].Monitor.write(centerText(currentButton.Label2,9))
pages[page].Monitor.setBackgroundColor(borderColor)
pages[page].Monitor.setCursorPos(currentColumn,currentRow+2)
pages[page].Monitor.setBackgroundColor(buttonColor)
pages[page].Monitor.setTextColor(buttonTextColor)
pages[page].Monitor.write(centerText(currentButton.Label3,9))
pages[page].Monitor.setBackgroundColor(borderColor)
end
end
end
function portalMessage(result,screenMessage,messageBackground,page) -- add background color
page=page or 1
messageBackground = messageBackground or portalMessageBackground
if(result) then
background = messageBackground
else
background = colors.pink
end
pages[page].Monitor=peripheral.wrap(pages[page].Side)
pages[page].Monitor.setCursorPos(8,9)
pages[page].Monitor.setBackgroundColor(background)
pages[page].Monitor.write(" ")
pages[page].Monitor.setCursorPos(8,10)
pages[page].Monitor.write(" ")
pages[page].Monitor.setCursorPos(8,11)
pages[page].Monitor.write(" ")
pages[page].Monitor.setCursorPos(8,12)
pages[page].Monitor.write(" ")
pages[page].Monitor.setCursorPos(8,13)
pages[page].Monitor.write(" ")
pages[page].Monitor.setCursorPos(8,11)
pages[page].Monitor.setTextColor(colors.black)
--Monitor.write(" OPENING PORTAL ")
pages[page].Monitor.write(screenMessage)
pages[page].Monitor.setBackgroundColor(borderColor)
end
-- BEGIN PROGRAM
rs.setBundledOutput(drawBridgeOutput,drawBridgeColor)
--drawGUI()
screen=1
term.restore()
term.clear()
if (showDebug) then
mon2 = peripheral.wrap("monitor_7")
mon2.clear()
end
drawGUI(1)
forceAnnounce()
currentPage = 1
while true do
local clickPage=1
for i = 1,#pages do
drawGUI(i)
end
event,arg1,arg2,arg3,arg4,a4g5 =os.pullEvent()
--event, mouseButton, x, y = os.pullEvent("monitor_touch")
if (showDebug) then
term.redirect(mon2)
print(""..event..","..(arg1 or "")..","..arg2 or ""..","..(arg3 or "")..","..(arg4 or "")..","..(arg5 or ""))
term.restore()
end
if (event=="monitor_touch") then
side = arg1
x=arg2
y=arg3
print("Monitor "..side..", x="..tostring(x)..", y="..tostring(y))
Monitor=peripheral.wrap(side)
for i=1,#pages do
if side==pages[i].Side then
clickPage=i
break
end
clickPage=1
end
if (y<5 or y>20) then
if (showDebug) then
term.redirect(mon2)
print("Non-Button Pressed")
term.restore()
end
else
buttonColumn = math.floor(x/columnWidth) +1
buttonRow = math.floor((y - 5)/linesPerRow)+1
currentRow=startingRow+((buttonRow-1)*linesPerRow)
currentColumn=(buttonColumn-1)*columnWidth+1
--print (""..buttonColumn.." C--R "..buttonRow)
if (showDebug) then
term.redirect(mon2)
print(""..y..","..x.." -- "..buttonRow..","..buttonColumn)
term.restore()
end
buttonNumber=(buttonRow-1)*numberColumns+buttonColumn
buttonPressed=pages[clickPage].Buttons[buttonNumber]
if (buttonPressed.Enabled) then
if (showDebug) then
term.redirect(mon2)
print(buttonPressed.Label)
term.restore()
end
portalMessage(true," CONFIGURING PORTAL ")
Monitor.setCursorPos(currentColumn,currentRow)
Monitor.setBackgroundColor(buttonSelectedBackground) -- change button color make selectable.
Monitor.setTextColor(buttonSelectedTextColor)
Monitor.write(centerText(buttonPressed.Label1,9))
Monitor.setBackgroundColor(borderColor)
Monitor.setCursorPos(currentColumn,currentRow+1)
Monitor.setBackgroundColor(buttonSelectedBackground)
Monitor.setTextColor(buttonSelectedTextColor)
Monitor.write(centerText(buttonPressed.Label2,9))
Monitor.setBackgroundColor(buttonSelectedBackground)
Monitor.setCursorPos(currentColumn,currentRow+2)
Monitor.setBackgroundColor(buttonSelectedBackground)
Monitor.setTextColor(colors.black)
Monitor.write(centerText(buttonPressed.Label3,9))
Monitor.setBackgroundColor(borderColor)
--sleep(1)
print("Requesting Book: "..buttonPressed.Label1.." "..buttonPressed.Label2.." "..buttonPressed.Label3)
rednet.send(turtles[clickPage],"GetBook"..tostring(buttonNumber))
local event, sender, message, _ = os.pullEvent("rednet_message")
--print ("Received Turtle: "..message)
if(message=="OK") then
portalMessage(true," OPENING PORTAL ",colors.lime)
rs.setBundledOutput(drawBridgeOutput,0)
local event, sender, message, _ = os.pullEvent("rednet_message")
portalMessage(true," CLOSING PORTAL ")
rs.setBundledOutput(drawBridgeOutput,drawBridgeColor)
print("Received from Turtle:"..message)
sleep(3)
else
portalMessage(false," PORTAL FAILURE ")
print("Portal Failure on Page "..tostring(clickPage)..", forcing Init.")
sleep(2)
forceInit(clickPage)
sleep(2)
end
else
print("Disabled Button pressed.")
portalMessage(false," BUTTON DISABLED ")
sleep(3)
end
end
elseif event=="rednet_message" and arg1~=os.getComputerID() then
sender = arg1
message = arg2
--print(tostring(sender).." sent "..message)
if(string.sub(message,1,6)=="TURTLE") then
turtlePage=tonumber(string.sub(message,7))
turtles[turtlePage]=sender
print("Turtle ID = "..turtles[turtlePage].." Page = "..turtlePage)
print("Sending CONTROL to "..sender)
rednet.send(sender,"CONTROL",true)
initTurtle(turtlePage)
end
elseif event=="char" then
if arg1=="1" then
forceInit(1)
elseif arg1=="2" then
forceInit(2)
elseif arg1=="3" then
forceInit(3)
elseif arg1=="4" then
forceInit(4)
elseif arg1=="a" then
forceAnnounce()
elseif arg1=="s" then
term.redirect(term.native)
elseif arg1=="t" then
--Monitor.monitorclose()
term.redirect(term.native)
break
end
end
end
The portal dialer turtle code can be downloaded at: http://pastebin.com/aysQLJG7
Portal Dialer Turtle Code
-- Portal Turtle v 2.2 (inspired by Armitige Shanks You Tube video of same)
-- by Mike Simpkins December 2013 (Creative Commons)
-- Paired with Portal Computer (http://pastebin.com/amCuLiLa)
local page = 1
local id = os.getComputerID()
-- set the id values to reflect this and other turtles
if (id==132) then page=1 elseif (id==129) then page = 2 else page = 3 end
local slots={}
control=0
local message=""
--Announce Turtle to Controller
function announceTurtle()
-- Turn on Modem
if(not rednet.isOpen("right")) then rednet.open("right") end
displayStatus("Announcing Turtle...")
repeat
timer=os.startTimer(3)
rednet.broadcast("TURTLE"..page)
repeat
event,control,message,_ = os.pullEvent()
--print(message or "null")
until ((event=="rednet_message" and message=="CONTROL") or (event=="timer" and control==timer))
until (message =="CONTROL")
initTurtle()
end
--Initialize turtle inventory and communicate with controller
function initTurtle()
displayStatus(" Initializing...",10,0)
--print ("Begin Init Turtle")
local zeroCount = 0
local slot
local status
--Reset Router
redstone.setOutput("bottom", false)
sleep (.2)
redstone.setOutput("bottom", true)
-- Check Inventory
for slot=1,16 do
slots[slot]=turtle.getItemCount(slot)
if (slots[slot]==0) then zeroCount=zeroCount+1 end
end
-- Turn on Modem
if(not rednet.isOpen("right")) then rednet.open("right") end
--print("modem is on")
if (zeroCount>0) then
status = textutils.serialize(slots)
else
status = "FULL"
end
repeat
--print("Sending message to "..control)
rednet.send(control,"InitTurtle"..page,true)
--print ("Message Sent")
repeat
timer=os.startTimer(3)
event,sender, message,_ = os.pullEvent("rednet_message")
--print ("Sender = "..sender.." message= "..message)
until ((event=="rednet_message" and sender==control) or (event=="timer" and sender==timer))
until (message==("PROCEED"..page))
--print ("Given PROCEED")
repeat
rednet.send(control,status,true)
repeat
sender, message,_ = rednet.receive()
until (sender==control)
until (message==status)
rednet.send(control,"OK"..page,true)
--print("Turtle"..page.." initialized")
displayStatus("Connected",12,0)
end
function displayStatus(state, line, clearScreen)
line = line or 7
clearScreen = clearScreen or 1
if (clearScreen==1) then term.clear() end
local position = math.ceil((39-#state)/2)
term.setCursorPos(position,line)
term.write(state)
end
function placeBook(book)
if (book>0 and book<17 and turtle.getItemCount(book)>0) then
displayStatus("Placing Book"..tostring(book),7)
turtle.select(book)
turtle.drop(1)
return "OK"
else
displayStatus("No Book in Slot",11,0)
return "NoBook"
end
end
function pullBook(book)
displayStatus("Pulling Book"..tostring(book),9,0)
-- force router to eject
redstone.setOutput("bottom", false)
sleep (.2)
-- check book placement, if placed in wrong slot move it
if turtle.getItemCount(book)==0 then
for slot=1,16 do
if (turtle.getItemCount(slot)~=slots[slot]) then
--print ("Bad Slot")
turtle.select(slot)
xferResult =true
if (not turtle.transferTo(book,1)) then
--print("could not moved book to "..tostring(slot))
slots[slot]=turtle.getItemCount(slot)
else
--print("moved book to "..tostring(slot))
break
end
end
end
end
redstone.setOutput("bottom", true) -- turns router back on
end
announceTurtle()
while true do
displayStatus("Awaiting Command")
event,arg1,arg2,arg3,arg4,a4g5 =os.pullEvent()
--print("Event ="..tostring(event).." Message "..tostring(arg2))
if event=="rednet_message" and arg1~=os.getComputerID() then
sender = arg1
message = arg2
if (sender==control or message=="ANNOUNCE") then --only messages from send or ANNOUNCE Broadcasts
--print("Control Message = "..message)
if (message=="ANNOUNCE") then
control = sender
announceTurtle()
elseif (message=="InitTurtle"..page) then --Request from Controller to init this turtle
initTurtle()
elseif (string.sub(message,1,7)=="GetBook") then
book = tonumber(string.sub(message,8))
result = placeBook(book)
rednet.send(control,result,true)
if (result=="OK") then
sleep(4)
rednet.send(control,"READY",true)
sleep(2)
pullBook(book)
end
else
rednet.send(control,"FAIL " ..message,true)
end
end
elseif (event=="char" and arg1=="a") then announceTurtle()
end
end
This was one of my first attempts at having computers/turtles announce themselves to each other and somewhat auto-configure. in addition, this was definitely my first attempt at using tables to hold both objects (like monitors) as well as data.
If you use this, you will need to modify the code to reflect your book inventory/titles as well as to place the labels of your monitors in the code.
If I rewrite this, I plan on using coroutines to make the handshaking between turtles and the portal computer work more gracefully. The portal computer will display a lot of troubleshooting information at present. Someday, I may pretty it up.
Hope it is helpful. Enjoy.
Edited on 01 February 2014 - 12:51 AM