Advertisement
s3ptum

Elevator!

Nov 23rd, 2013
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2. Elevator Control Setup by Hamish Robertson
  3. Aliases: OminousPenguin, MC username: Peren
  4.  
  5. Licence: Creative Commons Attribution-NonCommercial-ShareAlike (http://creativecommons.org/licenses/by-nc-sa/3.0/)
  6.  
  7. This is a LUA program for ComputerCraft, a Minecraft mod by Daniel Ratcliffe aka dan200 (http://www.computercraft.info/)
  8. This program is for controlling elevators from the Railcraft mod (http://www.railcraft.info/)
  9. For help and feedback please use this forum thread: http://www.computercraft.info/forums2/index.php?/topic/1302-railcraft-mod-elevator-control/
  10.  
  11. This is version 2b. It is in the beta release stage and so there may be bugs. If you believe you have found a bug, please report it at the above forum thread.
  12.  
  13. You are permitted to modify and or build upon this work.
  14. If you make your own version publicly available, then please also publish it at the above forum thread. Thank you and happy coding!
  15.  
  16. NOTE: This is the setup program. It will create a file called elevator.cfg and download the main program to elevator-main.lua
  17.  
  18. Use Ctrl+T to terminate the program
  19. --]]
  20.  
  21. CHANNEL_ELEVATOR = 34080
  22.  
  23. function writeToPos(x, y, str)
  24.     term.setCursorPos(x, y)
  25.     term.write(str)
  26. end
  27. function clearArea(x1,y1,x2,y2)
  28.     for i=y1,y2 do
  29.         writeToPos(x1,i,string.rep(" ",x2-x1))
  30.     end
  31. end
  32. function eventHandle(tHandlers, f, ...)
  33.     f = tHandlers[f]
  34.     if type(f) == "function" then return f(...) end
  35. end
  36. function debug(msg)
  37.     print(msg)
  38.     os.pullEvent("key")
  39. end
  40. function printSetupHeader(saving)
  41.     term.clear()
  42.     writeToPos(2,2,"====================[ Setup ]====================")
  43.     if saving then writeToPos(5,5,"Saving data... "); term.setCursorBlink(true) end
  44. end
  45.  
  46. function getModemSide()
  47.     -- Find all attached modems
  48.     local sides = {"left","right","top","bottom","back","front"}
  49.     local i = 1
  50.     while i <= #sides do
  51.         if peripheral.getType(sides[i]) ~= "modem" then
  52.             table.remove(sides,i)
  53.         else
  54.             i = i + 1
  55.         end
  56.     end
  57.  
  58.     if #sides == 0 then
  59.         return nil
  60.     elseif #sides == 1 then
  61.         return sides[1]
  62.     end
  63.  
  64.     -- If there is more than one modem attached, ask user to choose one
  65.     local selected = 1
  66.     local function redraw()
  67.         printSetupHeader()
  68.         writeToPos(7,9,"Use the modem on the          side")
  69.         for i=1,#sides do
  70.             if (i == selected) then
  71.                 writeToPos(29,9,sides[i])
  72.             else
  73.                 if (9-selected+i)<9 then
  74.                     term.setCursorPos(29,(8-selected+i))
  75.                 else
  76.                     term.setCursorPos(29,(10-selected+i))
  77.                 end
  78.                 term.write(sides[i])
  79.             end
  80.         end--for
  81.         writeToPos(4,18,"[ Arrow keys to select, Enter to confirm ]")
  82.     end--redraw()
  83.  
  84.     redraw(); -- First draw
  85.  
  86.     while true do
  87.         local _, keycode = os.pullEvent ("key")
  88.         if (keycode == 200) then -- up
  89.             if selected > 1 then selected = selected-1 end
  90.         elseif (keycode == 208) then -- down
  91.             if selected < 6 then selected = selected+1 end
  92.         elseif (keycode == 28) then -- enter
  93.             return sides[selected]
  94.         end
  95.         redraw()
  96.     end
  97. end--getModemSide()
  98.  
  99. function getElevatorID()
  100.     local elevatorID
  101.     printSetupHeader()
  102.     writeToPos(3, 4, "Searching for other elevators.")
  103.     writeToPos(3, 6, "This may take a few seconds...")
  104.     writeToPos(5, 10, "(Remember that rain reduces modem range)")
  105.     local modem = peripheral.wrap(modemSide)
  106.     modem.open(os.getComputerID())
  107.     modem.transmit(CHANNEL_ELEVATOR, os.getComputerID(), "ELEV\030ALL\030DISCOVER") -- Ask all elevator terminals in range to tell us their elevator ID
  108.     local tElevatorIDs = {}
  109.     local mt = {
  110.         tMeta = {},
  111.         iIndex = 1,
  112.         __newindex = function(t,k,v)
  113.             this = getmetatable(t)
  114.             if this.tMeta[k] ~= true then
  115.                 this.tMeta[k] = true
  116.                 rawset(t,this.iIndex,k)
  117.                 this.iIndex = this.iIndex + 1
  118.             end
  119.         end,
  120.     }
  121.     setmetatable(tElevatorIDs,mt)
  122.     local _, _, sChannel, sReplyChannel, sMessage
  123.     local discoveryTimer
  124.     local tHandlers = {
  125.         modem_message = function (_, sChannel, sReplyChannel, sMessage, nDistance)
  126.             discoveryTimer = os.startTimer(3) -- Reset timer
  127.             local iter = string.gmatch(sMessage, "([^\030]+)")
  128.             if sChannel == os.getComputerID() and iter() == "ELEV" then
  129.                 local eID = iter()
  130.                 if iter() == "ID" then
  131.                     tElevatorIDs[eID] = true
  132.                 end
  133.             end
  134.         end,
  135.         timer = function (timerID)
  136.             if timerID == discoveryTimer then   return true end
  137.         end
  138.     }
  139.     discoveryTimer = os.startTimer(3) -- Loop will timeout after three seconds of not receiving an event
  140.     while true do
  141.         local v = eventHandle(tHandlers, os.pullEvent())
  142.         if v then break end
  143.     end
  144.     writeToPos(3, 6, "Press any key to continue...  ") -- Pause to let them read the message about rain
  145.     os.pullEvent("key")
  146.  
  147.     local function getCustomID()
  148.         writeToPos(5, 7, "Please specify an ID: ")
  149.         writeToPos(2, 9, "IDs can have letters, numbers and other characters")
  150.         term.setCursorPos(27, 7); term.setCursorBlink(true)
  151.         return io.read()
  152.     end
  153.  
  154.     printSetupHeader()
  155.     if #tElevatorIDs == 0 then
  156.         writeToPos(2, 5, "No existing elevators detected.")
  157.         elevatorID = getCustomID()
  158.     else
  159.         writeToPos(2, 5, "The following elevator IDs were detected:")
  160.         writeToPos(3, 18, "Press Enter to use the selected ID")
  161.         writeToPos(3, 19, "Press Tab to create a new elevator ID")
  162.         local selected = 1
  163.         for k,v in ipairs(tElevatorIDs) do
  164.             writeToPos(5, 6+k, v)
  165.         end
  166.         writeToPos(3,7,">")
  167.         local function updateSelection(previousSelection)
  168.             writeToPos(3,6+previousSelection," ")
  169.             writeToPos(3,6+selected,">")
  170.         end
  171.         while true do
  172.             local _, keycode = os.pullEvent ("key")
  173.             if (keycode == 200) then -- up
  174.                 previousSelection = selected
  175.                 if selected > 1 then selected = selected-1 end
  176.             elseif (keycode == 208) then -- down
  177.                 previousSelection = selected
  178.                 if selected < #tElevatorIDs then selected = selected+1 end
  179.             elseif (keycode == 28) then -- enter
  180.                 elevatorID = tElevatorIDs[selected]
  181.                 break
  182.             elseif (keycode == 15) then -- tab
  183.                 clearArea(2,5,52,9)
  184.                 elevatorID = getCustomID()
  185.                 break
  186.             end
  187.             updateSelection(previousSelection)
  188.         end
  189.     end
  190.     return elevatorID
  191. end--getElevatorID()
  192.  
  193. function getFloorName()
  194.     printSetupHeader()
  195.     writeToPos(7,9,"Enter a name/label for this floor: ")
  196.     term.setCursorPos(14,11); term.setCursorBlink(true)
  197.     local name
  198.     repeat
  199.         name = io.read()
  200.     until name ~= ""
  201.     return name
  202. end--getFloorName()
  203.  
  204. function getGPS()
  205.     printSetupHeader()
  206.     writeToPos(5, 5, "Waiting for GPS response... ")
  207.     term.setCursorPos(5,7)
  208.     local x, y, z = gps.locate(2)
  209.     if x ~= nil then
  210.         term.write("... coordinates received")
  211.         writeToPos(5, 9, "Start GPS host in the background?")
  212.         local _, keycode, selected = nil, nil, 1
  213.         writeToPos(14,11,"[ Yes ]             No")
  214.         while true do
  215.             term.setCursorPos(14,11)
  216.             _, keycode = os.pullEvent ("key")
  217.             if (keycode == 205) or (keycode == 49) then -- right
  218.                 if selected == 1 then
  219.                     selected = 2
  220.                     term.write("  Yes             [ No ]")
  221.                 end
  222.             elseif (keycode == 203) or (keys.getName(keycode) == n) then -- left
  223.                 if selected == 2 then
  224.                     selected = 1
  225.                     term.write("[ Yes ]             No  ")
  226.                 end
  227.             elseif (keycode == 28) then -- enter
  228.                 if selected == 1 then
  229.                     return x,y,z
  230.                 else
  231.                     return nil, y
  232.                 end
  233.             end
  234.         end--while
  235.     else -- We didn't get coords from GPS
  236.         term.write("... could not determine coordinates")
  237.         return
  238.     end
  239. end--getGPS()
  240.  
  241. function getCoordsInput()
  242.     printSetupHeader()
  243.     writeToPos(8,7,"x coordinate:")
  244.     writeToPos(8,8,"y coordinate:")
  245.     writeToPos(8,9,"z coordinate:")
  246.     writeToPos(4,13,"Important: If your GPS hosts are all in a")
  247.     writeToPos(4,14,"vertical line (same x & y coordinates), then")
  248.     writeToPos(4,15,"you need to place another host off to the side")
  249.     writeToPos(4,16,"to enable an accurate GPS fix")
  250.     writeToPos(4,17,"(Usage: gps host x y z")
  251.     term.setCursorPos(22,7); term.setCursorBlink(true)
  252.    
  253.     local selected, inputs = 1, {"","",""}
  254.    
  255.     local function redraw()
  256.         term.setCursorPos(22+inputs[selected]:len(),6+selected)
  257.     end
  258.    
  259.     local eventHandlers = {
  260.         key = function(keycode)
  261.             if (keycode == 200) and (selected > 1) then -- up
  262.                 selected = selected-1
  263.                 redraw(selected);
  264.             elseif (selected < 3) and ((keycode == 208) or (keycode == 28)) then -- down
  265.                 selected = selected+1
  266.                 redraw(selected);
  267.             elseif (keycode == 28) then -- enter
  268.                 for i,input in ipairs(inputs) do
  269.                     if inputs[selected] == "" then return end
  270.                 end
  271.                 return inputs[1], inputs[2], inputs[3]
  272.             elseif (keycode == 14) and inputs[selected] ~= "" then -- backspace
  273.                     inputs[selected] = inputs[selected]:sub(1,-2)
  274.                     term.setCursorPos(22+inputs[selected]:len(),6+selected)
  275.                     term.write(" ")
  276.                     term.setCursorPos(22+inputs[selected]:len(),6+selected)
  277.             end
  278.         end,
  279.  
  280.         char = function(c)
  281.             if (inputs[selected]:len() < 4) and (string.find(c, "[%d\-]") ~= nil) then -- number entered
  282.                 inputs[selected] = inputs[selected]..c
  283.                 term.write(c)
  284.             end
  285.         end,
  286.  
  287.         handle = function (self, f, ...)
  288.             f = self[f]
  289.             if type(f) == "function" then return f(...) end
  290.         end
  291.     }
  292.     while true do
  293.         local x,y,z = eventHandlers:handle(os.pullEvent())
  294.         if x then return x,y,z end
  295.     end
  296. end--getCoordsInput
  297.  
  298. function getFloorCoords()
  299.     -- We need at least the y (height) coordinate so we can know what order the floors are in
  300.     printSetupHeader()
  301.     writeToPos(4,4,"The y (height) coordinate is required so that")
  302.     writeToPos(4,5,"floors can be listed in the correct order.")
  303.     writeToPos(4,7,"You have a few options:")
  304.     writeToPos(6,10,"1. Enter y coordinate:")
  305.     writeToPos(6,12,"2. Use GPS (requires 4 GPS hosts)")
  306.     writeToPos(6,14,"3. Enter x,y,z and then this computer")
  307.     writeToPos(13,15,"can become a GPS host.")
  308.     writeToPos(7,16,"(recommended if you have over 4 floors)")
  309.     writeToPos(2,19,"(Press F3 to view player coordinates)")
  310.    
  311.     local selected, line, y = 1, {10,12,14}, ""
  312.  
  313.     local function redraw(i, clear)
  314.         term.setCursorPos(3,8+(2*i))
  315.         local t = (clear and write(" ")) or write("[")
  316.         term.setCursorPos(49,8+(2*i))
  317.         local t = clear and write(" ") or write("]")
  318.         term.setCursorPos(29,10)
  319.     end
  320.  
  321.     redraw(1)
  322.     term.setCursorBlink(true)
  323.  
  324.     local eventHandlers = {
  325.         key = function(keycode)
  326.             if (keycode == 200) then -- up
  327.                 if selected > 1 then
  328.                     redraw(selected, true)
  329.                     selected = selected-1
  330.                     if selected == 1 then term.setCursorBlink(true) end
  331.                     redraw(selected);
  332.                 end
  333.             elseif (keycode == 208) then -- down
  334.                 if selected < 3 then
  335.                     redraw(selected, true)
  336.                     selected = selected+1
  337.                     term.setCursorBlink(false)
  338.                     redraw(selected);
  339.                 end
  340.             elseif (keycode == 28) then -- enter
  341.                 if ((selected == 1) and (y ~= "")) then
  342.                     return true, nil, y
  343.                 elseif selected == 2 then
  344.                     return true, getGPS()
  345.                 elseif selected == 3 then
  346.                     return true, getCoordsInput() -- input all 3
  347.                 end
  348.             elseif (keycode == 14) then -- backspace
  349.                 if ((selected == 1) and (y ~= "")) then
  350.                     y = y:sub(1,-2)
  351.                     term.setCursorPos(29+y:len(),10)
  352.                     term.write(" ")
  353.                     term.setCursorPos(29+y:len(),10)
  354.                 end
  355.             end
  356.         end,
  357.  
  358.         char = function(c)
  359.             if (selected == 1) and ((y:len() < 4) and (string.find(c, "%d") ~= nil)) then -- number entered
  360.                 y = y..c
  361.                 term.setCursorPos(28+y:len(),10)
  362.                 term.write(c)
  363.             end
  364.         end,
  365.  
  366.         handle = function (self, f, ...)
  367.             f = self[f]
  368.             if type(f) == "function" then return f(...) end
  369.         end
  370.     }
  371.     while true do
  372.         local RETURN,x,y,z = eventHandlers:handle(os.pullEvent())
  373.         if RETURN then return x,y,z end
  374.     end
  375. end--getFloorCoords()
  376.  
  377. fs.delete("elevator-main.lua")
  378. if not shell.run("pastebin", "get", "iJWyUQVr", "elevator-main.lua") then
  379.     print("Failed to download main program. Try manually from pastebin: iJWyUQVr\n(this is just the setup component)")
  380.     return
  381. end
  382.  
  383. modemSide = getModemSide()
  384. if modemSide == nil then
  385.     printSetupHeader()
  386.     writeToPos(15,6,"! No modem detected !")
  387.     writeToPos(8,9,"A modem is required for")
  388.     writeToPos(8,11,"communication with the other floors")
  389.     writeToPos(4,13,"Please attach a modem then try again")
  390.     return -- terminate program
  391. end
  392.  
  393. local elevatorID = getElevatorID()
  394.  
  395. local floorName = getFloorName()
  396.  
  397. local x,y,z
  398.  
  399. while true do
  400.     x,y,z = getFloorCoords()
  401.     if y==nil then
  402.         writeToPos(5, 11, "Press any key to continue...")
  403.         os.pullEvent("key")
  404.     else
  405.         break
  406.     end
  407. end
  408. local coords = y
  409. if x and y then
  410.     coords = x.."\31"..y.."\31"..z
  411. end
  412.  
  413. printSetupHeader(true)
  414. configPath = shell.resolve(".").."/elevator.cfg"
  415. fs.delete(configPath)
  416. local file = io.open(configPath, "w")
  417. file:write(modemSide.."\n")
  418. file:write(elevatorID.."\n")
  419. file:write(coords.."\n")
  420. file:write(y.."\31"..floorName)
  421. file:close()
  422. term.write("Done")
  423.  
  424. writeToPos(5,7,"Setting elevator-main.lua to run on startup... ")
  425.  
  426. file = io.open("/startup", "w")
  427. file:write("shell.run(\"/"..shell.resolve(".").."/elevator-main.lua\")")
  428. file:close()
  429. term.write("Done")
  430.  
  431. writeToPos(5, 9, "Press any key to reboot...")
  432. os.pullEvent("key")
  433. os.reboot()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement