FalloutOS/fallout_craftos.lua

564 lines
14 KiB
Lua
Executable file

local output = "bottom" --output side
local wordFile = "/fos/codes" --where the words are stored
local textColor = colors.lime
local attempts = 4
local permLockout = false --lock the terminal permanently?
local randomPass = true -- fallout style?
local PredefinedPass = "undefined"
local usedWords = {}
local status = {}
function addCustomStatus(message)
table.insert(status, message)
end
--check for advanced monitor
if not term.isColor() then
print("This program needs an advanced monitor.")
return
end
--check for wordFile
if not fs.exists(wordFile) then
print("The word file \""..wordFile.."\" is not populated.")
shell.run("cd /fos")
shell.run("updateWordList")
return
end
if not fs.exists("/fosdata/fo4_term.sys") then
-- Generate the default config
local h = fs.open("/fosdata/fo4_term.sys", "w")
h.writeLine("Password: undefined")
h.writeLine("Random: false")
h.close()
end
--centers the x value of a string
function center(str,y)
local maxX,maxY = term.getSize()
term.setCursorPos(math.floor(maxX/2)-math.floor(string.len(str)/2),y)
term.write(str)
end
--locks the terminal
function lockout()
term.clear()
term.setTextColor(textColor)
center("TERMINAL LOCKED",8)
center("PLEASE CONTACT AN ADMINISTRATOR",10)
local h = fs.open("/fosdata/lock_status","w")
h.writeLine("Locked: true")
h.close()
--center("DEBUG MODE ENABLED. TERMINATING",14)
-- os.reboot()
sleep(15 * 1000)
os.reboot()
end
--check for permLock
if not fs.exists("/fosdata/lock_status") then
local h = fs.open("/fosdata/lock_status","w")
h.writeLine("Locked: false")
h.close()
else
local h = fs.open("/fosdata/lock_status","r")
local isLocked = string.sub(h.readLine(),9)
if isLocked=="true" and permLockout then
lockout()
end
end
if fs.exists("/fosdata/fo4_term.sys") then
local h = fs.open("/fosdata/fo4_term.sys", "r")
while true do
local line = h.readLine()
if(line == nil)then break end
if (string.sub(line,1, 10) == "Password: ") then
PredefinedPass = string.sub(line, 11):upper()
--addCustomStatus(PredefinedPass)
elseif (string.sub(line,1,9) == "Random: ") then
randomPass = string.sub(line,10)
--addCustomStatus(randomPass)
end
end
end
function main()
local rows=12
local cols=10
require ("settingsFile")
readSettings()
if isLocked == "N" then
shell.run("mainMenu")
return
end
term.clear()
term.setCursorPos(1,1)
local dict = readWords(wordFile)
local eString1 = getEncoded(rows*cols,dict)
local eString2 = getEncoded(rows*cols,dict)
drawTitle()
drawAttempts(attempts)
drawHex(2,7)
drawHex(20,7)
drawEncoded(9,7,rows,cols,eString1)
drawEncoded(27,7,rows,cols,eString2)
if(randomPass) then
PredefinedPass=getPass()
end
if not fs.exists("/fosdata/crash.state") then
eventListener(eString1,eString2,PredefinedPass)
end
term.setCursorPos(1,1)
end
function getStatus(choice,pass)
local sameChars = commonLetters(choice,pass)
table.insert(status,string.upper(choice))
if sameChars==#pass and string.len(choice)==string.len(pass) then
table.insert(status,"Exact match!")
table.insert(status,"Please wait")
table.insert(status,"while system")
table.insert(status,"is accessed.")
else
table.insert(status,"Entry denied")
--table.insert(status,sameChars.."/"..string.len(pass).." correct.")
table.insert(status, "Likeness: "..sameChars)
attempts=attempts-1
end
if attempts==0 then
lockout()
end
end
function drawStatus()
local startX=38
local startY=16
local currentStat=#status
repeat
if status[currentStat]==nil then break end
clearFrom(startX,startY)
term.setCursorPos(startX,startY)
term.write(">"..status[currentStat])
currentStat=currentStat-1
startY=startY-1
until startY<=6
end
function success()
shell.run("/fos/mainMenu")
end
--highlights part of an eString
--detects keypresses
function eventListener(leftStr,rightStr,pass)
local side="left" --which eString is it
local charPos=1 --which number character
local cmdLineX,cmdLineY=38,18
local selection = string.sub(leftStr,1,1)
local onWord=false
local cursorX,cursorY=9,7
local upperX,upperY=36,18 --upper limits
local lowerX,lowerY=9,7 --lower limits
local keys = {262,263,264,265}
highlight(cursorX,cursorY,selection)
while true do
local ev,p1,p2,p3 = os.pullEventRaw()
--addCustomStatus("EV"..ev)
--addCustomStatus("P1"..p1)
--addCustomStatus("P2"..tostring(p2))
--addCustomStatus("P3"..tostring(p3))
drawStatus()
if ev == "terminate" then
addCustomStatus("Unable to")
addCustomStatus("terminate")
addCustomStatus("program")
addCustomStatus(" ")
addCustomStatus("System locked")
elseif ev=="key_up" then
if inTable(p1,keys) and not onWord then
lowlight(cursorX,cursorY,selection)
elseif inTable(p1,keys) and onWord then
if side=="left" then
lowWord(selection,leftStr,side)
else
lowWord(selection,rightStr,side)
end
end
if p1==265 and cursorY>lowerY then --up arrow
cursorY=cursorY-1
elseif p1==264 and cursorY<upperY then --down arrow
cursorY=cursorY+1
elseif p1==263 and cursorX>lowerX then --left arrow
if cursorX==27 then
side="left"
cursorX=cursorX-9
else
cursorX=cursorX-1
end
elseif p1==262 and cursorX<upperX then --right arrow
if cursorX==18 then
side="right"
cursorX=cursorX+9
else
cursorX=cursorX+1
end
elseif p1==257 then --enter key
getStatus(selection:upper(),pass:upper())
drawStatus()
drawAttempts(attempts)
if selection:upper()==pass:upper() then
success()
end
end
elseif ev=="mouse_click" and p1==1 then --left mouse button
if lowerX<=p2 and p2<=upperX and lowerY<=p3 and p3<=upperY then
cursorX,cursorY=p2,p3
-- debug: exit the code
-- return
if side=="left" then
charPos=math.floor(((cursorY-7)*10)+(cursorX-9)+1)
selection=string.sub(leftStr,charPos,charPos)
else
charPos=math.floor(((cursorY-7)*10)+(cursorX-27)+1)
selection=string.sub(rightStr,charPos,charPos)
end
if isalpha(selection) and side=="left" then
selection = findWord(cursorX,cursorY,charPos,leftStr,side)
lightWord(selection,leftStr,side)
onWord=true
elseif isalpha(selection) and side=="right" then
selection = findWord(cursorX,cursorY,charPos,rightStr,side)
lightWord(selection,rightStr,side)
onWord=true
else
onWord=false
highlight(cursorX,cursorY,selection)
end
clearFrom(cmdLineX,cmdLineY)
term.setCursorPos(cmdLineX,cmdLineY)
term.write("> "..selection)
getStatus(selection:upper(),pass:upper())
drawStatus()
drawAttempts(attempts)
if selection:upper() == pass:upper() then
success()
end
end
end
if side=="left" then
charPos=math.floor(((cursorY-7)*10)+(cursorX-9)+1)
selection=string.sub(leftStr,charPos,charPos)
else
charPos=math.floor(((cursorY-7)*10)+(cursorX-27)+1)
selection=string.sub(rightStr,charPos,charPos)
end
if isalpha(selection) and side=="left" then
selection = findWord(cursorX,cursorY,charPos,leftStr,side)
lightWord(selection,leftStr,side)
onWord=true
elseif isalpha(selection) and side=="right" then
selection = findWord(cursorX,cursorY,charPos,rightStr,side)
lightWord(selection,rightStr,side)
onWord=true
else
onWord=false
highlight(cursorX,cursorY,selection)
end
clearFrom(cmdLineX,cmdLineY)
term.setCursorPos(cmdLineX,cmdLineY)
term.write("> "..selection)
end
end
function lightWord(sel,eString,side)
local j=1
local l,r = string.find(eString,sel)
for i=l,r do
local x,y=posToCoords(i,side)
highlight(x,y,string.sub(sel,j,j))
j=j+1
end
end
function lowWord(sel,eString,side)
local j=1
local l,r = string.find(eString,sel)
for i=l,r do
local x,y = posToCoords(i,side)
lowlight(x,y,string.sub(sel,j,j))
j=j+1
end
end
function findWord(x,y,charPos,eString,side)
--check left and right
local left = charPos
local right = charPos
while isalpha(string.sub(eString:upper(),left-1,left-1)) do
left=left-1
end
while isalpha(string.sub(eString:upper(),right+1,right+1)) do
right=right+1
end
--highlight the word
for i=left,right do
local x,y = posToCoords(i,side)
highlight(x,y,string.sub(eString:upper(),i,i))
end
return(string.sub(eString:upper(),left,right))
end
function posToCoords(pos,side)
local x,y=0,0
if side=="left" then
if pos%10~=0 then
x=pos%10+8
y=math.floor(pos/10)+7
else
x=10+8
y=math.floor(pos/10)+6
end
else
if pos%10~=0 then
x=pos%10+26
y=math.floor(pos/10)+7
else
x=10+26
y=math.floor(pos/10)+6
end
end
return x,y
end
function highlight(x,y,sel)
term.setBackgroundColor(textColor)
term.setTextColor(colors.black)
term.setCursorPos(x,y)
term.write(sel)
term.setBackgroundColor(colors.black)
term.setTextColor(textColor)
end
function lowlight(x,y,sel)
term.setBackgroundColor(colors.black)
term.setTextColor(textColor)
term.setCursorPos(x,y)
term.write(sel)
end
--returns a password from the usedWords list
function getPass()
return(usedWords[math.random(1,#usedWords)])
end
function drawTitle()
term.setCursorPos(2,2)
term.setTextColor(textColor)
term.write("ROBCO INDUSTRIES (TM) TERMLINK PROTOCOL")
term.setCursorPos(2,3)
term.write("ENTER PASSWORD NOW")
end
function drawAttempts(a)
term.setCursorPos(2,5)
term.setTextColor(textColor)
term.clearLine()
term.write(a.." ATTEMPT(S) LEFT: ")
local x = 21
for i=1,a do
term.setBackgroundColor(textColor)
term.setCursorPos(x,5)
term.write(" ")
x = x + 2
end
term.setBackgroundColor(colors.black)
end
function drawHex(x,y)
local rows = 12
term.setTextColor(textColor)
for i=1,rows do
term.setCursorPos(x,y)
local hstring="0x"
for j=1,4 do hstring=hstring..randomHex() end
term.write(hstring)
y = y + 1
end
end
--returns string containing random nonletter characters
--and various words. does not have '\n' included
function getEncoded(size,words)
local step = 1
local totalWords=0
local curWord = nil
local onWord = false
local charIter = 1 --what letter in curWord are we at?
local chance = 0
local encodedString=nonletter()
local lastIsWord=false
--fills encodedString with nonletter chars and words
repeat
step=step+1
chance = math.random(1,13)
if chance==6 and not onWord and not lastIsWord and totalWords<=8 then
local reps=0
repeat
if reps>20 then break end
curWord=words[math.random(1,#words)]
reps=reps+1
until not inTable(curWord,usedWords) and step+#curWord<size
if reps<=20 then onWord=true end
end
--determines whether to add random nonletter or char from curWord
if onWord then
encodedString=encodedString..string.sub(curWord,charIter,charIter)
charIter=charIter+1
if charIter>#curWord then
table.insert(usedWords,curWord)
onWord=false
totalWords=totalWords+1
lastIsWord=true
charIter=1
end
else
encodedString=encodedString..nonletter()
lastIsWord=false
end
until string.len(encodedString)==size
return encodedString
end
function isalpha(char)
local alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i=1,string.len(alpha) do
if string.sub(alpha,i,i)==char:upper() then return true end
end
return false
end
--lightS is a table {x1,y1} and lightE is table {x2,y2}
function drawEncoded(x,y,rows,cols,eString,lightS,lightE)
term.setTextColor(textColor)
local curX=x
local curY=y
for i=1,rows*cols do
term.setCursorPos(curX,curY)
term.write(string.sub(eString,i,i))
if i%cols==0 then
curY=curY+1
curX=x
else
curX=curX+1
end
end
end
--read the codewords from the file
--returns list
function readWords(fileName)
local dict = {}
local h = fs.open(fileName,"r")
for word in string.gmatch(h.readAll(), "%a+") do table.insert(dict,word) end
return dict
end
function findPattern(text,pattern,start)
return string.sub(text,string.find(text,pattern,start))
end
--returns one nonletter char (random)
function nonletter()
local possible = {'!','@','#','$','%','^','&','*',
'(',')','_','-','+','=','[','{',
']','|',',','\'','\"','}',
';',':','.','>','<','?'}
return(possible[math.random(1,#possible)])
end
--returns one valid hex num (random)
function randomHex()
local possible = {'A','B','C','D','E','F'}
for i=0,9 do
table.insert(possible,i)
end
return(possible[math.random(1,#possible)])
end
--returns int of same letters in same positions in two strings.
function commonLetters(s1,s2)
charsInCommon=0
local long,short=nil,nil
if string.len(s1:upper())>=string.len(s2:upper()) then long,short=s1:upper(),s2:upper()
else long,short=s2:upper(),s1:upper() end
for i=1,#long do
if string.sub(long,i,i)==string.sub(short,i,i) then
charsInCommon=charsInCommon+1
elseif string.sub(short,i,i)==nil then
break
end
end
return charsInCommon
end
--clears a line from x,y till the end of the screen
function clearFrom(x,y)
term.setCursorPos(x,y)
for i=0,51-x do
term.setCursorPos(x+i,y)
term.write(" ")
end
end
--checks if a value is in a given table
function inTable(val,t)
for k,v in ipairs(t) do
if v==val then
return true
end
end
return false
end
function flush(startLine, endLine)
for x = startLine, endLine do
term.setCursorPos(1,x)
term.clearLine()
end
end
main()
if fs.exists ("/fosdata/crash.state") then
flush(5, 18)
term.setCursorPos(2,5)
print("ROBCO INDUSTRIES DEBUG UTILITY")
print("")
print(PredefinedPass)
print(getPass())
return
end