Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- PocketOS ATM - touch-screen deposits into the PocketOS bank.
- --
- -- Hardware: an ADVANCED computer with a wireless modem, a Create
- -- display target ("create_target") whose display lists the deposit
- -- chest's contents, and redstone (or an Advanced Peripherals redstone
- -- integrator) that moves the deposited items away when pulsed.
- --
- -- Flow: player taps START, types their pocket computer ID, puts iron/
- -- gold/diamonds in the chest, taps DEPOSIT ITEMS, confirms - the items
- -- get taken and the value lands in their bank account (they also get a
- -- receipt in Messages). Runs once and takes over startup as a kiosk.
- -------------------------------------------------- CONFIG - edit me --
- local RATES = { iron = 1, gold = 5, diamond = 25 } -- $ per item
- local ACCEPT_SIDE = "bottom" -- redstone side that accepts the items
- local IDLE_TIME = 45 -- seconds before returning to the start
- -- Runs when a deposit is accepted: move the items out of the chest.
- local redint = peripheral.find("redstoneIntegrator")
- local function acceptItems()
- local out = redint or redstone
- out.setOutput(ACCEPT_SIDE, true)
- sleep(1)
- out.setOutput(ACCEPT_SIDE, false)
- end
- -----------------------------------------------------------------------
- local NICE = { iron = "Iron", gold = "Gold", diamond = "Diamond" }
- if not term.isColor or not term.isColor() then
- print("The ATM needs an advanced (gold) computer.")
- return
- end
- local target = peripheral.find("create_target")
- local hasModem = false
- for _, side in ipairs(peripheral.getNames()) do
- if peripheral.getType(side) == "modem" then
- if pcall(rednet.open, side) then hasModem = true end
- end
- end
- local w, h = term.getSize()
- -- take over startup so the ATM boots as a kiosk
- do
- local cur = ""
- if fs.exists("startup.lua") then
- local f = fs.open("startup.lua", "r")
- cur = f.readAll() or ""
- f.close()
- end
- if not cur:find("atm.lua", 1, true) then
- local f = fs.open("startup.lua", "w")
- f.write("-- ATM kiosk (created by atm.lua)\n")
- f.write("shell.run(\"atm.lua\")\n")
- f.close()
- end
- end
- local function fill(x, y, wd, ht, bg)
- term.setBackgroundColor(bg)
- for i = 0, ht - 1 do
- term.setCursorPos(x, y + i)
- term.write(string.rep(" ", wd))
- end
- end
- local function center(y, s, fg)
- term.setCursorPos(math.floor((w - #s) / 2) + 1, y)
- term.setTextColor(fg)
- term.setBackgroundColor(colors.black)
- term.write(s)
- end
- local function button(x, y, label, bg)
- fill(x, y, #label + 2, 1, bg)
- term.setCursorPos(x + 1, y)
- term.setTextColor(colors.white)
- term.write(label)
- return { x1 = x, y1 = y, x2 = x + #label + 1, y2 = y }
- end
- local function hit(r, x, y)
- return r and x >= r.x1 and x <= r.x2 and y >= r.y1 and y <= r.y2
- end
- local function screenMsg(title, lines, buttons)
- term.setBackgroundColor(colors.black)
- term.clear()
- center(4, title, colors.white)
- for i, s in ipairs(lines) do
- center(6 + i, s, colors.lightGray)
- end
- local regions = {}
- local total = #buttons - 1
- for _, b in ipairs(buttons) do total = total + #b[1] + 2 end
- local bx = math.floor((w - total) / 2) + 1
- for i, b in ipairs(buttons) do
- regions[i] = button(bx, 9 + #lines, b[1], b[2])
- bx = bx + #b[1] + 3
- end
- while true do
- local _, _, mx, my = os.pullEvent("mouse_click")
- for i, r in ipairs(regions) do
- if hit(r, mx, my) then return i end
- end
- end
- end
- ------------------------------------------------------------- bank --
- local bankId
- local function findBank()
- if bankId then return bankId end
- local ok, cfg = pcall(dofile, "/pocketos/config.lua")
- if ok and type(cfg) == "table" and tonumber(cfg.bank) then
- bankId = tonumber(cfg.bank)
- return bankId
- end
- bankId = rednet.lookup("pocketos.bank")
- return bankId
- end
- local function request(msg)
- if not hasModem then return nil, "No modem on the ATM" end
- local bid = findBank()
- if not bid then return nil, "No bank found" end
- rednet.send(bid, msg, "pocketos.bank")
- local id, resp = rednet.receive("pocketos.bank", 3)
- if id == bid and type(resp) == "table" then return resp end
- return nil, "Bank not answering"
- end
- -- read the Create display target listing the deposit chest
- local function scanDeposit()
- local found, total = {}, 0
- if not target then return found, 0 end
- for i = 1, 8 do
- local ok, line = pcall(target.getLine, i)
- if ok and type(line) == "string" and line ~= "" then
- local amount = tonumber(line:match("(%d+)"))
- if amount then
- local low = line:lower()
- local kind
- if low:find("iron", 1, true) then
- kind = "iron"
- elseif low:find("gold", 1, true) then
- kind = "gold"
- elseif low:find("diamond", 1, true) then
- kind = "diamond"
- end
- if kind and RATES[kind] then
- local value = amount * RATES[kind]
- found[#found + 1] = { n = amount, kind = kind, value = value }
- total = total + value
- end
- end
- end
- end
- return found, total
- end
- --------------------------------------------------------------- ui --
- local function keypad(title)
- local entry = ""
- local layout = {
- { "1", "2", "3" },
- { "4", "5", "6" },
- { "7", "8", "9" },
- { "C", "0", "OK" },
- }
- while true do
- term.setBackgroundColor(colors.black)
- term.clear()
- center(2, title, colors.white)
- center(4, entry == "" and "_" or entry, colors.yellow)
- local regions = {}
- local x0 = math.floor(w / 2) - 8
- for r = 1, 4 do
- for cn = 1, 3 do
- local label = layout[r][cn]
- local bx = x0 + (cn - 1) * 6
- local by = 4 + r * 2
- fill(bx, by, 5, 1, label == "OK" and colors.green or colors.gray)
- term.setCursorPos(bx + math.floor((5 - #label) / 2), by)
- term.setTextColor(colors.white)
- term.write(label)
- regions[#regions + 1] = { x1 = bx, x2 = bx + 4, y = by, label = label }
- end
- end
- center(14, "[ Cancel ]", colors.red)
- center(h, "Your ID is shown in Settings on your pocket", colors.gray)
- local e, a, b, c = os.pullEvent()
- if e == "mouse_click" then
- if c == 14 then return nil end
- for _, r in ipairs(regions) do
- if c == r.y and b >= r.x1 and b <= r.x2 then
- if r.label == "OK" then
- if #entry > 0 then return tonumber(entry) end
- elseif r.label == "C" then
- entry = ""
- elseif #entry < 7 then
- entry = entry .. r.label
- end
- end
- end
- elseif e == "char" and a:match("^%d$") and #entry < 7 then
- entry = entry .. a
- elseif e == "key" then
- if a == keys.enter and #entry > 0 then return tonumber(entry) end
- if a == keys.backspace then entry = entry:sub(1, -2) end
- end
- end
- end
- local function idleScreen()
- term.setBackgroundColor(colors.black)
- term.clear()
- center(3, "PocketOS ATM", colors.yellow)
- center(5, string.format("Iron $%d Gold $%d Diamond $%d",
- RATES.iron, RATES.gold, RATES.diamond), colors.lightGray)
- local bw, bh = 15, 3
- local bx = math.floor((w - bw) / 2) + 1
- fill(bx, 8, bw, bh, colors.green)
- term.setCursorPos(bx + math.floor((bw - 5) / 2), 9)
- term.setTextColor(colors.white)
- term.write("START")
- if not target then
- center(13, "! No Create target attached", colors.red)
- end
- if not hasModem then
- center(14, "! No wireless modem", colors.red)
- end
- center(h, "ATM #" .. os.getComputerID(), colors.gray)
- while true do
- local e = os.pullEvent("mouse_click")
- if e then return end
- end
- end
- local function depositFlow(account)
- local items, total = scanDeposit()
- if not target then
- screenMsg("ATM Error", { "No Create display", "target attached." },
- { { "OK", colors.blue } })
- return nil
- end
- if total <= 0 then
- screenMsg("Nothing to Deposit", {
- "Put iron, gold or",
- "diamonds into the",
- "deposit chest first.",
- }, { { "OK", colors.blue } })
- return nil
- end
- term.setBackgroundColor(colors.black)
- term.clear()
- center(2, "Deposit for #" .. account, colors.white)
- local y = 4
- for _, it in ipairs(items) do
- center(y, it.n .. " " .. NICE[it.kind] .. " = $" .. it.value, colors.lightGray)
- y = y + 1
- end
- center(y + 1, "Total: $" .. total, colors.yellow)
- local accept = button(math.floor(w / 2) - 11, y + 3, "Accept", colors.green)
- local cancel = button(math.floor(w / 2) + 3, y + 3, "Cancel", colors.red)
- while true do
- local _, _, mx, my = os.pullEvent("mouse_click")
- if hit(accept, mx, my) then break end
- if hit(cancel, mx, my) then return nil end
- end
- center(y + 5, "Processing...", colors.gray)
- pcall(acceptItems)
- local resp, err
- for _ = 1, 3 do
- resp, err = request({ type = "deposit", account = account, amount = total })
- if resp then break end
- sleep(1)
- end
- if resp and resp.ok then
- screenMsg("Deposited!", {
- "$" .. total .. " added.",
- "New balance: $" .. (resp.balance or "?"),
- }, { { "OK", colors.green } })
- return resp.balance
- end
- screenMsg("Bank Offline!", {
- "Items were taken but",
- "not credited. Tell an",
- "admin: #" .. account .. " +$" .. total,
- }, { { "OK", colors.red } })
- return nil
- end
- local function accountScreen(account, info)
- local balance = info.balance or 0
- local label = info.label
- while true do
- term.setBackgroundColor(colors.black)
- term.clear()
- center(2, "#" .. account .. (label and (" " .. label) or ""), colors.white)
- center(4, "Balance: $" .. balance, colors.yellow)
- local bw, bh = 25, 5
- local bx = math.floor((w - bw) / 2) + 1
- local by = 7
- fill(bx, by, bw, bh, colors.green)
- term.setCursorPos(bx + math.floor((bw - 13) / 2), by + 2)
- term.setTextColor(colors.white)
- term.write("DEPOSIT ITEMS")
- fill(w - 7, h - 1, 6, 1, colors.gray)
- term.setCursorPos(w - 6, h - 1)
- term.setTextColor(colors.white)
- term.write("Done")
- center(h, "Insert items into the chest first", colors.gray)
- local t = os.startTimer(IDLE_TIME)
- local e, a, b, c = os.pullEvent()
- if e == "timer" and a == t then
- return
- elseif e == "mouse_click" then
- if b >= bx and b <= bx + bw - 1 and c >= by and c <= by + bh - 1 then
- local nb = depositFlow(account)
- if nb then balance = nb end
- elseif c == h - 1 and b >= w - 7 then
- return
- end
- end
- end
- end
- --------------------------------------------------------------- run --
- while true do
- idleScreen()
- local account = keypad("Enter your pocket ID")
- if account then
- term.setBackgroundColor(colors.black)
- term.clear()
- center(9, "Checking...", colors.gray)
- local info, err = request({ type = "info", account = account })
- if info and info.ok then
- accountScreen(account, info)
- else
- screenMsg("No Bank", { tostring((info and info.err) or err or "Offline") },
- { { "OK", colors.red } })
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment