This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
surferpup's profile picture

Portal Dialing Computer with Turtles

Started by surferpup, 12 January 2014 - 02:11 AM
surferpup #1
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.


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
Black Snake 666 #2
Posted 05 June 2014 - 03:16 PM
do you have a version for 1.64pr2?
because your Version brings a lot of error Codes! And im new in programming. Hope you can help me.
BlockSmith #3
Posted 07 June 2014 - 05:57 AM
Very nicely done.