Sedrowow

participant pocket

Feb 27th, 2026 (edited)
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.58 KB | Gaming | 0 0
  1. -- Participant Pocket Client
  2. -- ComputerCraft / CC:Tweaked
  3.  
  4. local CHANNEL = 44551
  5. local SERVER_PROTOCOL = "cc_quiz_scoreboard"
  6.  
  7. local modemSide
  8. local username = nil
  9. local disqualified = false
  10.  
  11. local currentState = {
  12.   mode = "hidden", -- hidden | reveal | disqualified | waiting
  13.   message = "Not registered yet.",
  14.   payload = nil
  15. }
  16.  
  17. local function formatPoints(value)
  18.   local points = tonumber(value) or 0
  19.   if points % 1 == 0 then
  20.     return tostring(math.floor(points))
  21.   end
  22.   return string.format("%.1f", points)
  23. end
  24.  
  25. local function findModemSide()
  26.   for _, side in ipairs(peripheral.getNames()) do
  27.     if peripheral.getType(side) == "modem" then
  28.       return side
  29.     end
  30.   end
  31.   return nil
  32. end
  33.  
  34. local function centerText(y, text, color)
  35.   local w, _ = term.getSize()
  36.   term.setCursorPos(1, y)
  37.   term.clearLine()
  38.   term.setTextColor(color or colors.white)
  39.   local x = math.max(1, math.floor((w - #text) / 2) + 1)
  40.   term.setCursorPos(x, y)
  41.   term.write(text)
  42. end
  43.  
  44. local function initNetwork()
  45.   modemSide = findModemSide()
  46.   if not modemSide then
  47.     error("No modem found. This pocket computer needs an ender modem.")
  48.   end
  49.  
  50.   if not rednet.isOpen(modemSide) then
  51.     rednet.open(modemSide)
  52.   end
  53. end
  54.  
  55. local function sendToServer(payload)
  56.   payload.channel = CHANNEL
  57.   rednet.broadcast(payload, SERVER_PROTOCOL)
  58. end
  59.  
  60. local function askUsername()
  61.   term.setBackgroundColor(colors.black)
  62.   term.setTextColor(colors.white)
  63.   term.clear()
  64.  
  65.   centerText(2, "CC Quiz Participant", colors.cyan)
  66.   centerText(4, "Enter username and press Enter", colors.lightGray)
  67.  
  68.   term.setCursorPos(2, 6)
  69.   term.setTextColor(colors.white)
  70.   write("> ")
  71.   local input = read()
  72.   input = tostring(input or ""):gsub("^%s+", ""):gsub("%s+$", "")
  73.  
  74.   if input == "" then
  75.     centerText(8, "Username cannot be empty.", colors.red)
  76.     sleep(1.2)
  77.     return askUsername()
  78.   end
  79.  
  80.   return input
  81. end
  82.  
  83. local function draw()
  84.   term.setBackgroundColor(colors.black)
  85.   term.clear()
  86.  
  87.   centerText(1, "Participant View", colors.cyan)
  88.   if username then
  89.     centerText(2, username, colors.white)
  90.   end
  91.  
  92.   if currentState.mode == "waiting" then
  93.     centerText(4, currentState.message or "Waiting for server...", colors.lightGray)
  94.  
  95.   elseif currentState.mode == "hidden" then
  96.     centerText(4, "Scoreboard Hidden", colors.yellow)
  97.     centerText(6, "Wait for administration reveal.", colors.lightGray)
  98.  
  99.   elseif currentState.mode == "disqualified" then
  100.     centerText(4, "DISQUALIFIED", colors.red)
  101.     centerText(6, currentState.message or "Removed by administration.", colors.lightGray)
  102.  
  103.   elseif currentState.mode == "reveal" then
  104.     local data = currentState.payload or {}
  105.     local row = 4
  106.  
  107.     centerText(row, string.format("Your Rank: #%d / %d", data.self.rank or 0, data.total or 0), colors.lime)
  108.     row = row + 1
  109.     centerText(row, string.format("Your Points: %s", formatPoints(data.self.points or 0)), colors.white)
  110.     row = row + 2
  111.  
  112.     centerText(row, "Top 3", colors.yellow)
  113.     row = row + 1
  114.     if data.top3 and #data.top3 > 0 then
  115.       local rendered = 0
  116.       for i = 1, #data.top3 do
  117.         local t = data.top3[i]
  118.         if not (data.self and t.id == data.self.id) then
  119.           centerText(row, string.format("%d. %s (%s)", t.rank, t.username, formatPoints(t.points)), colors.white)
  120.           row = row + 1
  121.           rendered = rendered + 1
  122.         end
  123.       end
  124.       if rendered == 0 then
  125.         centerText(row, "(You are in Top 3)", colors.lightGray)
  126.         row = row + 1
  127.       end
  128.     else
  129.       centerText(row, "No ranking data", colors.lightGray)
  130.       row = row + 1
  131.     end
  132.  
  133.     row = row + 1
  134.     if data.above then
  135.       centerText(row, string.format("Above: %d. %s (%s)", data.above.rank, data.above.username, formatPoints(data.above.points)), colors.lightGray)
  136.       row = row + 1
  137.     else
  138.       centerText(row, "Above: nobody", colors.lightGray)
  139.       row = row + 1
  140.     end
  141.  
  142.     if data.below then
  143.       centerText(row, string.format("Below: %d. %s (%s)", data.below.rank, data.below.username, formatPoints(data.below.points)), colors.lightGray)
  144.     else
  145.       centerText(row, "Below: nobody", colors.lightGray)
  146.     end
  147.   end
  148.  
  149.   local _, h = term.getSize()
  150.   centerText(h, "Q: re-register", colors.gray)
  151. end
  152.  
  153. local function handleMessage(senderId, msg, protocol)
  154.   if protocol ~= SERVER_PROTOCOL then
  155.     return
  156.   end
  157.  
  158.   if type(msg) ~= "table" or not msg.type then
  159.     return
  160.   end
  161.  
  162.   if msg.type == "register_ok" then
  163.     currentState.mode = "waiting"
  164.     currentState.message = "Registered. Waiting for scoreboard state..."
  165.   elseif msg.type == "register_error" then
  166.     currentState.mode = "waiting"
  167.     currentState.message = msg.message or "Registration failed."
  168.   elseif msg.type == "score_hidden" then
  169.     currentState.mode = "hidden"
  170.     currentState.message = msg.message
  171.     currentState.payload = nil
  172.   elseif msg.type == "score_reveal" then
  173.     currentState.mode = "reveal"
  174.     currentState.payload = msg
  175.   elseif msg.type == "disqualified" then
  176.     disqualified = true
  177.     currentState.mode = "disqualified"
  178.     currentState.message = msg.reason or "You were disqualified."
  179.     currentState.payload = nil
  180.   elseif msg.type == "force_reset" then
  181.     currentState.mode = "waiting"
  182.     currentState.message = msg.reason or "Reset requested by administration."
  183.     currentState.payload = nil
  184.     draw()
  185.     sleep(1)
  186.     os.reboot()
  187.   end
  188. end
  189.  
  190. local function register()
  191.   sendToServer({
  192.     type = "register",
  193.     username = username
  194.   })
  195.  
  196.   sendToServer({
  197.     type = "request_state"
  198.   })
  199. end
  200.  
  201. local function heartbeatLoop()
  202.   while true do
  203.     sleep(5)
  204.     sendToServer({ type = "heartbeat" })
  205.     if not disqualified then
  206.       sendToServer({ type = "request_state" })
  207.     end
  208.   end
  209. end
  210.  
  211. local function receiverLoop()
  212.   while true do
  213.     local senderId, msg, protocol = rednet.receive(SERVER_PROTOCOL, 1)
  214.     if senderId then
  215.       handleMessage(senderId, msg, protocol)
  216.       draw()
  217.     end
  218.   end
  219. end
  220.  
  221. local function inputLoop()
  222.   while true do
  223.     local event, key = os.pullEvent("key")
  224.     if key == keys.q then
  225.       disqualified = false
  226.       username = askUsername()
  227.       currentState.mode = "waiting"
  228.       currentState.message = "Registering..."
  229.       currentState.payload = nil
  230.       register()
  231.       draw()
  232.     end
  233.   end
  234. end
  235.  
  236. local function main()
  237.   initNetwork()
  238.  
  239.   username = askUsername()
  240.   currentState.mode = "waiting"
  241.   currentState.message = "Registering..."
  242.   register()
  243.   draw()
  244.  
  245.   parallel.waitForAny(receiverLoop, heartbeatLoop, inputLoop)
  246. end
  247.  
  248. main()
  249.  
Advertisement
Add Comment
Please, Sign In to add comment