cshwayze

Keypad Door (ComputerCraft)

Oct 10th, 2025 (edited)
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.18 KB | Gaming | 0 0
  1. -- keypad.lua (no door label on monitor)
  2.  
  3. local PROTOCOL = "doorAuth.v1"
  4. local DOOR_TAG = "lobby" -- <--- set this to your door tag
  5.  
  6. -- ---------- Modem ----------
  7. local function openModems()
  8. for _, side in ipairs(rs.getSides()) do
  9. if peripheral.getType(side) == "modem" then rednet.open(side) end
  10. end
  11. end
  12.  
  13. local function findServer()
  14. return rednet.lookup(PROTOCOL, "DoorAuthServer")
  15. end
  16.  
  17. -- ---------- Terminal UI ----------
  18. local function terminalPIN()
  19. term.clear()
  20. term.setCursorPos(1,1)
  21. write("Enter PIN: ")
  22. local pin = read("*") -- masked
  23. return pin
  24. end
  25.  
  26. -- ---------- Autoscale + Layout ----------
  27. local function tryScales(mon, scales)
  28. for _, s in ipairs(scales) do
  29. mon.setTextScale(s)
  30. local w,h = mon.getSize()
  31. if w >= 10 and h >= 9 then return s,w,h end
  32. end
  33. return nil, mon.getSize()
  34. end
  35.  
  36. local function decideLayout(w,h)
  37. return { compact = (w < 24 or h < 12) }
  38. end
  39.  
  40. -- ---------- Drawing ----------
  41. local function drawKeypad(mon, layout)
  42. mon.setBackgroundColor(colors.black)
  43. mon.setTextColor(colors.white)
  44. mon.clear()
  45.  
  46. local pinY = layout.compact and 1 or 2
  47. mon.setCursorPos(2, pinY); mon.write("PIN:")
  48.  
  49. local keys = {
  50. {"1","2","3"},
  51. {"4","5","6"},
  52. {"7","8","9"},
  53. {"CLR","0","OK"},
  54. }
  55.  
  56. local startX, startY, bw, bh, gap
  57. if layout.compact then
  58. bw, bh, gap = 3, 1, 1
  59. startX = 2
  60. startY = pinY + 2
  61. else
  62. bw, bh, gap = 6, 3, 1
  63. startX = 3
  64. startY = pinY + 2
  65. end
  66.  
  67. for r=1,4 do
  68. for c=1,3 do
  69. local x = startX + (c-1)*(bw+gap)
  70. local y = startY + (r-1)*(bh+gap)
  71. for yy=y, y+bh-1 do
  72. mon.setCursorPos(x, yy)
  73. mon.write(string.rep(" ", bw))
  74. end
  75. local label = keys[r][c]
  76. mon.setCursorPos(x + math.floor((bw-#label)/2), y + math.floor(bh/2))
  77. mon.write(label)
  78. end
  79. end
  80.  
  81. return { keys=keys, startX=startX, startY=startY, bw=bw, bh=bh, gap=gap, pinY=pinY }
  82. end
  83.  
  84. -- ---------- Keypad Loop ----------
  85. local function keypadLoop(mon)
  86. tryScales(mon, {0.5, 0.75, 1})
  87. local w,h = mon.getSize()
  88. local layout = decideLayout(w,h)
  89. local geo = drawKeypad(mon, layout)
  90.  
  91. local pin = ""
  92. local function refreshPIN()
  93. local x = 6
  94. mon.setCursorPos(x, geo.pinY)
  95. mon.write(string.rep(" ", (layout.compact and 10 or 20)))
  96. mon.setCursorPos(x, geo.pinY)
  97. mon.write(string.rep("*", #pin))
  98. end
  99. refreshPIN()
  100.  
  101. while true do
  102. local event, p1, p2, p3 = os.pullEvent()
  103.  
  104. if event == "monitor_touch" then
  105. local touchedSide, x, y = p1, p2, p3
  106. if peripheral.getName(mon) == touchedSide then
  107. for r=1,4 do
  108. for c=1,3 do
  109. local bx = geo.startX + (c-1)*(geo.bw+geo.gap)
  110. local by = geo.startY + (r-1)*(geo.bh+geo.gap)
  111. if x >= bx and x < bx+geo.bw and y >= by and y < by+geo.bh then
  112. local label = geo.keys[r][c]
  113. if label == "OK" then return pin
  114. elseif label == "CLR" then pin = ""; refreshPIN()
  115. else
  116. if #pin < 12 then pin = pin .. label; refreshPIN() end
  117. end
  118. end
  119. end
  120. end
  121. end
  122.  
  123. elseif event == "char" then
  124. local ch = p1
  125. if ch:match("%d") and #pin < 12 then pin = pin .. ch; refreshPIN() end
  126.  
  127. elseif event == "key" then
  128. local keyCode = p1
  129. if keyCode == keys.backspace then pin = pin:sub(1, #pin-1); refreshPIN()
  130. elseif keyCode == keys.enter then return pin end
  131. end
  132. end
  133. end
  134.  
  135. -- ---------- Verify ----------
  136. local function trim(s) return tostring(s or ""):gsub("^%s+",""):gsub("%s+$","") end
  137.  
  138. local function verifyWithServer(serverID, tag, pin)
  139. rednet.send(serverID, {type="verify", tag=tag, pin=pin}, PROTOCOL)
  140. local timer = os.startTimer(3)
  141. while true do
  142. local ev = { os.pullEvent() }
  143. if ev[1] == "rednet_message" then
  144. local id, msg, proto = ev[2], ev[3], ev[4]
  145. if id==serverID and proto==PROTOCOL and type(msg)=="table"
  146. and msg.type=="verify_result" and msg.tag==tag then
  147. return msg.ok
  148. end
  149. elseif ev[1] == "timer" and ev[2] == timer then
  150. return false,"timeout"
  151. end
  152. end
  153. end
  154.  
  155. -- ---------- Main ----------
  156. local function main()
  157. openModems()
  158. local mon = peripheral.find("monitor")
  159.  
  160. local server = findServer()
  161. if not server then
  162. print("Finding server...")
  163. while not server do sleep(2); server = findServer() end
  164. end
  165. print("[Keypad] Server #" .. server .. " | Door '"..DOOR_TAG.."'")
  166.  
  167. while true do
  168. local pin = mon and keypadLoop(mon) or terminalPIN()
  169. pin = trim(pin)
  170.  
  171. if pin == "" then
  172. if mon then drawKeypad(mon, decideLayout(mon.getSize())) else print("No PIN entered.") end
  173. else
  174. local ok = verifyWithServer(server, DOOR_TAG, pin)
  175. if mon then
  176. local msg = ok and "GRANTED" or "DENIED"
  177. mon.setCursorPos(2, (decideLayout(mon.getSize())).compact and 1 or 1)
  178. mon.write("Access: "..msg.." ")
  179. sleep(ok and 0.8 or 1.2)
  180. drawKeypad(mon, decideLayout(mon.getSize()))
  181. else
  182. print(ok and "Access GRANTED" or "Access DENIED")
  183. end
  184. end
  185. end
  186. end
  187.  
  188. main()
  189.  
Advertisement
Add Comment
Please, Sign In to add comment