From f493405b4889710f49955ac55dfc0e91ffc7d895 Mon Sep 17 00:00:00 2001 From: Moonlit Productions Date: Mon, 29 Dec 2025 00:27:25 -0500 Subject: [PATCH] added Iris Password system --- config.lua | 13 +++ display.lua | 70 +++++++++++++ startup.lua | 285 ++++++++++++++++++++++++++++++++++++++-------------- utils.lua | 37 +++++++ 4 files changed, 332 insertions(+), 73 deletions(-) diff --git a/config.lua b/config.lua index 97cc08e..31b6ebb 100644 --- a/config.lua +++ b/config.lua @@ -27,6 +27,19 @@ config.autoCloseIrisOnIncoming = true config.irisCloseDelay = 0.1 -- seconds before closing iris on incoming config.autoOpenIrisAfterDisconnect = true +-- Iris password (set to nil to disable remote password unlock) +config.irisPassword = "1234" + +--------------------------------------------- +-- MESSAGING +--------------------------------------------- + +-- Program version (sent to remote gates when connection established) +config.programVersion = "1.0" + +-- Enable computer-to-computer messaging through stargate +config.enableMessaging = true + --------------------------------------------- -- SECURITY --------------------------------------------- diff --git a/display.lua b/display.lua index 638e688..cbacda3 100644 --- a/display.lua +++ b/display.lua @@ -219,4 +219,74 @@ function display.showMainMenu() display.drawIrisStatus() end +--------------------------------------------- +-- PASSWORD PROMPT +--------------------------------------------- + +function display.showPasswordPrompt() + mon.setBackgroundColor(colors.black) + mon.clear() + mon.setTextScale(1) + + mon.setBackgroundColor(colors.blue) + mon.setCursorPos(7, 2) + mon.write("IRIS PASSWORD") + + mon.setBackgroundColor(colors.black) + mon.setCursorPos(7, 5) + mon.write("Enter Code:") + + -- Draw number pad (3x4 grid) + local oldterm = term.redirect(mon) + + -- Numbers 1-9 + local row = 7 + for i = 1, 9 do + local col = 8 + ((i - 1) % 3) * 5 + if (i - 1) % 3 == 0 and i > 1 then + row = row + 3 + end + paintutils.drawFilledBox(col, row, col + 3, row + 2, colors.green) + mon.setCursorPos(col + 1, row + 1) + mon.write(tostring(i)) + end + + -- Bottom row: Clear (0), Zero, Enter + paintutils.drawFilledBox(8, 16, 11, 18, colors.red) + mon.setCursorPos(9, 17) + mon.write("CLR") + + paintutils.drawFilledBox(13, 16, 16, 18, colors.green) + mon.setCursorPos(14, 17) + mon.write("0") + + paintutils.drawFilledBox(18, 16, 21, 18, colors.blue) + mon.setCursorPos(18, 17) + mon.write("OK") + + term.redirect(oldterm) + display.drawIrisStatus() +end + +function display.updatePasswordDisplay(password) + mon.setBackgroundColor(colors.black) + mon.setCursorPos(7, 6) + mon.write(string.rep("*", #password) .. " ") +end + +function display.showPasswordResult(success) + mon.setBackgroundColor(colors.black) + mon.setCursorPos(7, 10) + if success then + mon.setTextColor(colors.green) + mon.write("ACCESS GRANTED") + mon.setTextColor(colors.white) + else + mon.setTextColor(colors.red) + mon.write("ACCESS DENIED") + mon.setTextColor(colors.white) + end + sleep(2) +end + return display diff --git a/startup.lua b/startup.lua index 5a344d0..27c4cf1 100644 --- a/startup.lua +++ b/startup.lua @@ -1,7 +1,7 @@ --[[ Stargate Control System - Main Entry Point For Stargate Journey Mod - AllTheMods 9 - + Comprehensive control program featuring: - Full dialing system with touch screen interface - Automatic iris control with security features @@ -95,7 +95,7 @@ end local function ParaDisconnect() local dx, dy = 0, 0 _, _, dx, dy = os.pullEvent("monitor_touch") - + if (dx ~= 0) and (dy ~= 0) then gate.disconnectStargate() redstone.setOutput("top", false) @@ -115,11 +115,11 @@ local function DisconnectCheck() local _, _, disCode = os.pullEvent("stargate_disconnected") redstone.setOutput("top", false) utils.log("Stargate disconnected (code: " .. tostring(disCode) .. ")") - + if config.autoOpenIrisAfterDisconnect then utils.openIris() end - + return 2 end @@ -128,36 +128,116 @@ local function Paratimeout() return 2 end +local function GetMessage() + local _, _, message = os.pullEvent("stargate_message_received") + return message +end + +local function HandlePasswordEntry() + -- Display password prompt + display.showPasswordPrompt() + + local password = "" + local entering = true + + while entering do + local x, y = GetClick() + + -- Check number buttons (1-9) + if y >= 7 and y <= 15 then + local row = math.floor((y - 7) / 3) + local col = math.floor((x - 8) / 5) + + if col >= 0 and col <= 2 and row >= 0 and row <= 2 then + local num = row * 3 + col + 1 + if num >= 1 and num <= 9 then + password = password .. tostring(num) + display.updatePasswordDisplay(password) + end + end + end + + -- Check bottom row buttons + if y >= 16 and y <= 18 then + if x >= 8 and x <= 11 then + -- Clear button + password = "" + display.updatePasswordDisplay(password) + elseif x >= 13 and x <= 16 then + -- Zero button + password = password .. "0" + display.updatePasswordDisplay(password) + elseif x >= 18 and x <= 21 then + -- OK button - submit password + entering = false + end + end + end + + -- Send password attempt + utils.sendPasswordAttempt(password) + + return password +end + +local function HandleIncomingPasswordRequest(password) + -- Check if password matches + if config.irisPassword and password == config.irisPassword then + utils.log("Correct password received, opening iris") + utils.openIris() + utils.sendPasswordResponse(true) + return true + else + utils.log("Incorrect password received: " .. password) + utils.sendPasswordResponse(false) + return false + end +end + local function MonitorRemoteIris() -- Continuously monitor remote iris state while connected + local lastIrisState = nil + while gate.isStargateConnected() do - sleep(2) -- Check every 2 seconds - + sleep(0.5) -- Check every half second + if transceiver then local remoteIrisState = transceiver.checkConnectedShielding() - - if remoteIrisState and remoteIrisState > 0 then - -- Remote iris closed or closing - if remoteIrisState == 100 then - utils.log("ALERT: Remote iris fully closed during connection!") + + -- Only update display if state changed + if remoteIrisState ~= lastIrisState then + if remoteIrisState and remoteIrisState > 0 then + -- Remote iris closed or closing + if remoteIrisState == 100 then + utils.log("ALERT: Remote iris fully closed during connection!") + else + utils.log("ALERT: Remote iris moving: " .. remoteIrisState .. "%") + end + + mon.setBackgroundColor(colors.red) + mon.clear() + mon.setTextScale(1) + mon.setCursorPos(6, 5) + mon.write("REMOTE IRIS") + mon.setCursorPos(8, 7) + if remoteIrisState == 100 then + mon.write("CLOSED!") + else + mon.write(remoteIrisState .. "% CLOSED") + end + mon.setCursorPos(3, 10) + mon.write("Connection unsafe") + display.drawIrisStatus() else - utils.log("ALERT: Remote iris closing: " .. remoteIrisState .. "%") + -- Remote iris is open (0 or nil) + if lastIrisState and lastIrisState > 0 then + -- Iris just opened + utils.log("Remote iris opened - connection safe") + end + display.showConnected(destAddressname, destAddress) end - - mon.setBackgroundColor(colors.red) - mon.clear() - mon.setTextScale(1) - mon.setCursorPos(6, 5) - mon.write("REMOTE IRIS") - mon.setCursorPos(8, 7) - if remoteIrisState == 100 then - mon.write("CLOSED!") - else - mon.write(remoteIrisState .. "% CLOSED") - end - mon.setCursorPos(3, 10) - mon.write("Connection unsafe") - display.drawIrisStatus() + + lastIrisState = remoteIrisState end end end @@ -175,18 +255,22 @@ local function handleIncomingWormhole() mon.setTextScale(1) mon.setCursorPos(9, 4) mon.write("INCOMING") - + incomingAddress = utils.addressToTable(incomingAddress) - + -- Check security local allowed, reason = utils.isAddressAllowed(incomingAddress) local addressString = gate.addressToString(incomingAddress) or "Unknown" - + utils.log("Incoming wormhole from: " .. addressString .. " " .. reason) - + -- Show incoming connection status display.showIncoming(addressString, allowed, reason) - + + -- Send version message to remote gate + sleep(0.5) -- Brief delay to ensure connection is stable + utils.sendVersionMessage() + -- Handle iris if config.autoCloseIrisOnIncoming then sleep(config.irisCloseDelay) @@ -196,21 +280,32 @@ local function handleIncomingWormhole() utils.closeIris() end end - + -- Monitor for entities disconnect = false while (disconnect == false) do -- parallel.waitForAny runs multiple functions at the same time and returns which one finished first - -- Here we're watching for 3 things simultaneously: + -- Here we're watching for 4 things simultaneously: -- 1 = EntityRead (someone/something came through the gate) -- 2 = DisconnectCheck (gate disconnected on its own) + -- 3 = GetMessage (received a message from remote gate) -- ParaDisconnect (user clicked screen to manually disconnect) -- Whichever happens first, that function returns and we handle it - local incomingcheck = parallel.waitForAny(EntityRead, DisconnectCheck, ParaDisconnect) - if (incomingcheck == 1) then + local result = parallel.waitForAny(EntityRead, DisconnectCheck, GetMessage, ParaDisconnect) + if (result == 1) then display.showEntity(incomingEntityType, incomingEntityName, allowed) incomingEntityType = "" incomingEntityName = "" + elseif (result == 3) then + -- Received a message + local message = GetMessage() + utils.log("Received message: " .. message) + + -- Check if it's a password attempt + if message:sub(1, 14) == "IRIS_PASSWORD:" then + local password = message:sub(15) + HandleIncomingPasswordRequest(password) + end else disconnect = true end @@ -223,42 +318,42 @@ end --------------------------------------------- local function dialGate(address) - tmp = deepCopy(address) + tmp = utils.deepCopy(address) table.remove(tmp) utils.log("Dialing: " .. gate.addressToString(tmp)) - + local gateType = gate.getStargateType() - + -- Manual Milky Way dialing with ring rotation if gateType == "sgjourney:milky_way_stargate" and config.manualDial == true then local addressLength = #address - + if addressLength == 8 then gate.setChevronConfiguration({ 1, 2, 3, 4, 6, 7, 8, 5 }) elseif addressLength == 9 then gate.setChevronConfiguration({ 1, 2, 3, 4, 5, 6, 7, 8 }) end - + local start = gate.getChevronsEngaged() + 1 - + for chevron = start, addressLength, 1 do local symbol = address[chevron] - + if chevron % 2 == 0 then gate.rotateClockwise(symbol) else gate.rotateAntiClockwise(symbol) end - + while (not gate.isCurrentSymbol(symbol)) do sleep(0) end - + gate.openChevron() sleep(1) gate.closeChevron() sleep(0.5) - + display.showDialing(chevron, symbol, gateType) end else @@ -271,17 +366,17 @@ local function dialGate(address) gate.setChevronConfiguration({ 1, 2, 3, 4, 5, 6, 7, 8 }) end end - + local start = gate.getChevronsEngaged() + 1 - + for chevron = start, #address, 1 do local symbol = address[chevron] - + gate.engageSymbol(symbol) sleep(config.gatespeed) - + display.showDialing(chevron, symbol, gateType) - + if (symbol) ~= 0 then if (gateType == "sgjourney:universe_stargate") or (gateType == "sgjourney:pegasus_stargate") then os.pullEvent("stargate_chevron_engaged") @@ -303,7 +398,7 @@ local function selectGateFromList() while dialing == false and selecting == true do selx, sely = GetClick() local buttonXY, computerAddresses, computerNames = display.getButtonData() - + for i = 1, #buttonXY do if (sely == buttonXY[i][3]) and ((selx >= buttonXY[i][1]) and (selx <= buttonXY[i][2])) then dialGate(computerAddresses[i]) @@ -319,78 +414,75 @@ local function selectGateFromList() end end end - + display.clearButtonData() return dialing end local function selectCategory() local state = true - + while state == true do display.selectionTabs() - + local tabx, taby = GetClick() y = 2 local count = 0 - + if (taby >= 2) and (taby <= 6) and ((tabx >= 2) and (tabx <= 13)) then if #addresses.MainGates ~= 0 then mon.setBackgroundColor(colors.black) mon.clear() mon.setBackgroundColor(colors.purple) count, y = display.screenWrite(addresses.MainGates, count, y) - + local returnstate = selectGateFromList() if returnstate == true then state = false end - + display.clearButtonData() else mon.setCursorPos(9, 7) mon.write("no gates available") sleep(5) end - elseif (taby >= 2) and (taby <= 6) and ((tabx >= 16) and (tabx <= 27)) then if #addresses.playerGates ~= 0 then mon.setBackgroundColor(colors.black) mon.clear() mon.setBackgroundColor(colors.green) count, y = display.screenWrite(addresses.playerGates, count, y) - + local returnstate = selectGateFromList() if returnstate == true then state = false end - + display.clearButtonData() else mon.setCursorPos(9, 7) mon.write("no gates available") sleep(5) end - elseif (((taby >= 8) and (taby <= 12)) and ((tabx >= 2) and (tabx <= 13))) and (config.canAccessHazardGates == true) then if (#addresses.hazardGates ~= 0) and (config.canAccessHazardGates == true) then mon.setBackgroundColor(colors.black) mon.clear() mon.setBackgroundColor(colors.red) count, y = display.screenWrite(addresses.hazardGates, count, y) - + local returnstate = selectGateFromList() if returnstate == true then state = false end - + display.clearButtonData() else mon.setCursorPos(9, 7) mon.write("no gates available") sleep(5) end - elseif (taby >= 17) and (tabx >= 23) then state = false totalstate = false @@ -403,18 +495,65 @@ local function handleOutgoingDial() totalstate = true local PDO = 0 PDO = parallel.waitForAny(selectCategory, Paratimeout) - + if (PDO == 1) and totalstate == true then sleep(1) - + os.pullEvent("stargate_outgoing_wormhole") - + + -- Wait briefly for version message from remote gate + local remoteHasComputer = false + local function WaitForVersion() + sleep(1) -- Wait up to 1 second for version message + return nil + end + + local result = parallel.waitForAny(GetMessage, WaitForVersion) + if result == 1 then + local message = GetMessage() + if message:sub(1, 6) == "SGCS_V" then + remoteHasComputer = true + local version = message:sub(7) + utils.log("Remote gate has control system version " .. version) + end + end + -- Check if remote iris is closed using transceiver local remoteIrisState = nil if transceiver then remoteIrisState = transceiver.checkConnectedShielding() end - + + -- If remote has computer + iris closed, offer password entry + if remoteHasComputer and remoteIrisState and remoteIrisState > 0 then + utils.log("Remote iris closed but computer detected - showing password prompt") + + local password = HandlePasswordEntry() + + -- Wait for response + local function WaitForResponse() + sleep(3) -- Wait up to 3 seconds for response + return nil + end + + result = parallel.waitForAny(GetMessage, WaitForResponse) + if result == 1 then + local response = GetMessage() + if response == "IRIS_OPEN" then + display.showPasswordResult(true) + utils.log("Password accepted - iris opened") + elseif response == "IRIS_DENIED" then + display.showPasswordResult(false) + utils.log("Password rejected") + end + end + + -- Re-check iris state after password attempt + if transceiver then + remoteIrisState = transceiver.checkConnectedShielding() + end + end + if remoteIrisState and remoteIrisState > 0 then -- Remote iris is closed (partially or fully) if remoteIrisState == 100 then @@ -422,7 +561,7 @@ local function handleOutgoingDial() else utils.log("WARNING: Remote iris is " .. remoteIrisState .. "% closed!") end - + mon.setBackgroundColor(colors.red) mon.clear() mon.setTextScale(1) @@ -441,7 +580,7 @@ local function handleOutgoingDial() -- Remote iris is open or no iris present display.showConnected(destAddressname, destAddress) end - + if (gate.isStargateConnected() == true) then -- parallel.waitForAny runs functions at the same time, returns which finished first -- While the wormhole is open, we wait for: @@ -454,7 +593,7 @@ local function handleOutgoingDial() dialing = false end end - + display.clearButtonData() destAddress = {} destAddressname = "" @@ -468,7 +607,7 @@ local function mainMenu() while true do display.showMainMenu() local answer = parallel.waitForAny(GetClick, GetActivation) - + if (answer == 1) then handleOutgoingDial() else diff --git a/utils.lua b/utils.lua index dbf8ecc..49056e3 100644 --- a/utils.lua +++ b/utils.lua @@ -136,4 +136,41 @@ function utils.getIrisState() return "NO IRIS" end +--------------------------------------------- +-- MESSAGING +--------------------------------------------- + +function utils.sendVersionMessage() + if config.enableMessaging then + local message = "SGCS_V" .. config.programVersion + gate.sendStargateMessage(message) + utils.log("Sent version message: " .. message) + return true + end + return false +end + +function utils.sendPasswordResponse(success) + if config.enableMessaging then + if success then + gate.sendStargateMessage("IRIS_OPEN") + utils.log("Sent iris open confirmation") + else + gate.sendStargateMessage("IRIS_DENIED") + utils.log("Sent iris access denied") + end + return true + end + return false +end + +function utils.sendPasswordAttempt(password) + if config.enableMessaging then + gate.sendStargateMessage("IRIS_PASSWORD:" .. password) + utils.log("Sent password attempt") + return true + end + return false +end + return utils