Lots of changes, almost exactly how I want it now

This commit is contained in:
Firepup Sixfifty 2024-04-27 16:00:01 -05:00
parent d502fd3ee5
commit e2b99a0270
Signed by: Firepup650
GPG key ID: 7C92E2ABBBFAB9BA
16 changed files with 383 additions and 57 deletions

5
.gitignore vendored
View file

@ -1 +1,4 @@
*.pyc
*.pyc
original**
test**
__pycache__**

BIN
audio/beep.wav Normal file

Binary file not shown.

BIN
audio/correctpass.wav Normal file

Binary file not shown.

BIN
audio/keyenter.wav Normal file

Binary file not shown.

BIN
audio/poweroff.wav Normal file

Binary file not shown.

BIN
audio/poweron.wav Normal file

Binary file not shown.

BIN
audio/wrongpass.wav Normal file

Binary file not shown.

View file

@ -4,17 +4,80 @@ import fallout_boot as boot
import fallout_locked as locked
import fallout_hack as hack
import fallout_selection as select
#import fallout_things as things
import fallout_data as data
from fallout_functions import soundTest, isQueueEmpty, addSound
from time import sleep
import sys
hard = False
if len(sys.argv) == 2 and sys.argv[1].lower() == 'hard':
if '--hard' in sys.argv:
hard = True
if boot.beginBoot(hard):
pwd = hack.beginLogin()
if pwd != None:
login.beginLogin(hard, 'ADMIN', pwd)
print(select.beginSelection())
else:
locked.beginLocked()
print('Login failed')
skip = False
if '--skip' in sys.argv:
skip = True
if '--skip-preload' not in sys.argv:
soundTest()
try:
addSound("poweron")
while not isQueueEmpty():
sleep(0.2)
if skip or boot.beginBoot(hard):
while not isQueueEmpty():
sleep(0.2)
pwd = None
if not skip:
pwd = hack.beginLogin()
else:
pwd = "VERYVERYSECUREPASSWORD"
if pwd != None:
login.beginLogin(hard, 'ADMIN', pwd)
while not isQueueEmpty():
sleep(0.2)
sel = 0
while sel != 3:
sel = select.beginSelection(data.ROBCO_HEADERS, data.SOFT_HEADERS, data.MAIN_MENU)
while not isQueueEmpty():
sleep(0.2)
if sel == 0:
loc = 0
while loc != 1:
MENU = [data.LOCK_MENU[tog][data.LOCK_CONDS[tog]] for tog in data.LOCK_CONDS.keys()]
MSGS = [data.LOCK_MSGS[tog][data.LOCK_CONDS[tog]] for tog in data.LOCK_CONDS.keys()]
loc = select.beginSelection(data.ROBCO_HEADERS, data.SOFT_HEADERS, MENU, MSGS)
if loc == 0:
if data.LOCK_CONDS['LOCKED']:
data.LOCK_CONDS['LOCKED'] = 0
else:
data.LOCK_CONDS['LOCKED'] = 1
elif sel == 1:
tur = 0
while tur != 2:
MENU = [data.TURRET_MENU[tog][data.TURRET_CONDS[tog]] for tog in data.TURRET_CONDS.keys()]
MSGS = [data.TURRET_MSGS[tog][data.TURRET_CONDS[tog]] for tog in data.TURRET_CONDS.keys()]
tur = select.beginSelection(data.TURRET_HEADERS, data.TURRET_HEADERS2, MENU, MSGS)
if tur == 0:
data.TURRET_CONDS['TARGETING'] = 1
elif tur == 1:
if data.TURRET_CONDS['ENABLED']:
data.TURRET_CONDS['ENABLED'] = 0
else:
data.TURRET_CONDS['ENABLED'] = 1
elif sel == 2:
log = 0
while log != data.LOG_RET_ID:
log = select.beginSelection(data.ROBCO_HEADERS, data.SOFT_HEADERS, data.LOG_NAMES)
if log != data.LOG_RET_ID:
select.beginSelection(data.ROBCO_HEADERS, data.LOGS[data.LOG_NAMES[log]].split("\n"), ["Return"])
else:
locked.beginLocked()
print('Login failed')
except KeyboardInterrupt:
pass
addSound("poweroff")
while not isQueueEmpty():
sleep(0.2)

View file

@ -58,7 +58,7 @@ def runBoot(scr, hardMode):
# input is entered for them
slowWrite(scr, '>')
curses.napms(INPUT_PAUSE)
slowWrite(scr, ENTRY_1 + '\n', TYPE_DELAY)
slowWrite(scr, ENTRY_1 + '\n', TYPE_DELAY, True)
slowWrite(scr, '\n' + MESSAGE_2 + '\n\n')
@ -73,10 +73,10 @@ def runBoot(scr, hardMode):
else:
slowWrite(scr, '>')
curses.napms(INPUT_PAUSE)
slowWrite(scr, ENTRY_2 + '\n', TYPE_DELAY)
slowWrite(scr, ENTRY_2 + '\n', TYPE_DELAY, True)
slowWrite(scr, '>')
curses.napms(INPUT_PAUSE)
slowWrite(scr, ENTRY_3 + '\n', TYPE_DELAY)
slowWrite(scr, ENTRY_3 + '\n', TYPE_DELAY, True)
slowWrite(scr, '\n' + MESSAGE_3 + '\n\n')
@ -88,7 +88,7 @@ def runBoot(scr, hardMode):
else:
slowWrite(scr, '>')
curses.napms(INPUT_PAUSE)
slowWrite(scr, ENTRY_4 + '\n', TYPE_DELAY)
slowWrite(scr, ENTRY_4 + '\n', TYPE_DELAY, True)
curses.napms(INPUT_PAUSE)
return True

147
fallout_data.py Normal file
View file

@ -0,0 +1,147 @@
####################### text strings ########################
ROBCO_HEADERS = (
'ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM',
'COPYRIGHT 2075-2077 ROBCO INDUSTRIES',
'-SERVER 6-',
''
)
TURRET_HEADERS = (
'-RobCo Trespasser Management System-',
'====================================',
''
)
TURRET_HEADERS2 = (
'RobcOS v.85',
'(C)2076 RobCo',
'========================',
'| User Log:',
'| >> Administrator (RobCoID 2398-H)',
'| >> New_Admin: FIRE PUP',
'| Welcome new user, FIRE PUP',
'| >> New_Targeting_Param:',
'| >>> FIRE PUP_userGroup',
''
)
SOFT_HEADERS = (
'\tSoftLock Solutions, Inc',
'"Your Security is Our Security"',
'>\\ Welcome, USER',
''
)
MAIN_MENU = (
'Lock Control',
'Turret Control',
'Read Log',
'Logoff Terminal'
)
LOCK_MENU = {
'LOCKED': ["Disengage Lock", "Engage Lock"],
'RETURN': ["Return"]
}
TURRET_MENU = {
'TARGETING': ["Re-configure Targeting Parameters", "<!>WARNING: No Targeting Data<!>"],
'ENABLED': ["Deactivate Turret System", "Activate Turret System"],
'RETURN': ["Return"]
}
TURRET_MSGS = {
'TARGETING': ['Target Data Cleared. Exercise Caution.', '<!>Please Exercise Caution<!>'],
'ENABLED': ['Powering Down...', 'Booting...'],
'RETURN': ['']
}
LOCK_MSGS = {
'LOCKED': ['Clearance granted, Unlocking...', 'Clearance granted, Locking...'],
'RETURN': ['']
}
TURRET_CONDS = {
'TARGETING': 0,
'ENABLED': 0,
'RETURN': 0
}
LOCK_CONDS = {
'LOCKED': 0,
'RETURN': 0
}
LOGS = {
'Megaton - Afterword': """USER: MOIRA BROWN
PASS: ***********
Date: 09.10.2297
Welcome, MOIRA. It is another lovely day for science!
DAILY LOG:
Experiment Reports:
Irradiated AgricultureGood response from mutfruit, strangely aggressive response to baseline sample. Purified water very helpful.
Deathclaw CommunicationNo language that I can discern, unless "Mutilating assistants" counts. What would they have to say, anyway?
Jefferson Purifier - Guards still refuse to allow access to see how the Purifier works. They say it's to prevent sabotage, but I think they aren't entirely certain.
Personal Note:
Just shipped out another crate of survival guides, and the caravans just can't seem to get enough of them. Sheriff Simms says they've really put Megaton on the mappretty ironic, since I've had to redraw that map about a million times since the first edition came out 20 years ago. At least all the attention means there's no shortage of assistants, but I'm never getting another assistant like the Lone Wanderer who stumbled into my shop so long ago.
Just about everyone in the Capital Wasteland has a story about the Lone Wanderer, even though precious few ever really knew him. But that doesn't stop them from telling crazy tall tales about how he saved their lives, or blew up a mountain, or ate a car or something. Heck, if you get Simms drunk, he'll tell you that his dad died because of the Wanderer, even though he saved the town. People can't even agree on whether the Wanderer was a man or a woman, much less a saint or a monster. But they all agree on one thing: the Lone Wanderer changed the Capital Wasteland.
Of course, that's why I'm working on the new book, compiling the best and most useful tales of the Lone Wanderer for the next generation. It's not easy sorting out all the conflicting stories, but that'll be half of the fun for the readers. More importantly, between all of those crazy stories of bravery, barbarity, and everything in-between, we can all find a reason to keep on fighting our war for survival.
I guess some things never change, huh?""",
'ERR - Ikkm00:Mvkz6x1ml:Nqtm': "[ERROR HX40-399: invalid decry.key]",
'Nuka Cola - Quantum Progress Report 0041': """Isotope CE770 has proven to be a disastrous failure. All of the test subjects suffered severe internal organ failures and died within three days of ingestion. We recommend the immediate destruction of container A32 in the production rooms and suggest switching to isotope CE772. Please send standard "Nuka Condolences" Fruit and Cheese Packages to test group member's families.""",
'Nuka Cola - Quantum Progress Report 0055': "Isotope CE772 has proven too damaging to the initial test group which now needs to be disbanded due to their reluctance to continue in our program. This group has suffered 4 fatalities, 12 major internal organ failures and 32 internal radiation burns. This is an unacceptable number of issues in a given test group and recommend we switch to an alternate isotope (such as CE774 or UR993).",
'Nuka Cola - Quantum Progress Report 0067': "Test subjects in the Nuka-Cola Quantum program are responding well to the reconfigured taste and the new isotope. The only listed side effects from the group are: 3 cases of dizziness, 1 case of nausea and 1 case of impaired vision. We find from a sampling of 50 that this is an acceptable number of cases and approve this product for production.",
'Nuka Cola - Company Announcement': "The Nuka-Cola Corporation is pleased to announce to all it's employees that the first shipments of our Nuka-Cola Quantum® are on their way to retailers in the Washington D.C. area! This flagship test market program is the culmination of a three year research program to bring the refreshing taste of Quantum to market. Congratulations to all employees on a job well done!",
'Nuka Cola - New Flavor Coming!': """Attention all Nuka-Cola Corporation Employees
We are very proud to announce that R&D has been completed on Nuka-Cola Clear! With an only minimal loss of life, we've been able to modify the look of Nuka-Cola but give it the same great taste. We will be submitting the product to Marketing shortly for bottle design and advertising strategies. From all of us in the Research Department, thanks for the support!""",
'Nuka Cola - From: Marketing': """The following locations have been accepted into the flagship Nuka-Cola Quantum test program. Please ensure that 1 (one) crate of Quantum is included with their regular deliveries along with the advertising package provided by our Marketing Department.
1. Paradise Falls Shopping Mart
2. Super Duper Mart
3. Old Olney Grocery""",
'Nuka Cola - Packing Line Instructions': """Welcome to the Nuka-Cola Packing Line Operator's Station! You are now instrumental in getting Nuka-Cola from our factory and to the public, so please read the simple instructions below. If you need assistance, please call x347 and ask for your Line Supervisor.
1. Access the Packing Terminal and choose desired inventory to load into Sorting Units.
2. Select "Activate Packing Line."
3. Monitor the Packing Line by listening for things such as mechanical screeching, explosions and/or human cries for help.
4. If there is an emergency, DO NOT PANIC! Simply call x347 and ask for your Line Supervisor. The Packing Line will automatically shut down in the event of an issue.
Remember, only you can prevent inventory loss by being attentive and vigilant!""",
'Nuka Cola - Packing Line Notice': """Attention all Packing Line employees!
Due to an oversight by the design department, the new Nuka-Cola Quantum bottles are slightly heavier than the standard Nuka-Cola bottles. As a result, the Packing Line is prone to jams and may cause damage to the equipment. Please DO NOT load Nuka-Cola Quantum bottles into the Sorting Units until further notice. All test samples of Quantum will be packaged by hand until a solution is reached.""",
'Nuka Cola - Stage One': """Stage One of the Nuka-Cola Quantum marketing will include: 2 (two) 15 (fifteen)-second television commercials, 4 (four) 10 (ten)-second radio commercials and a highway billboard campaign.
The spots on TV and radio will tease the consumer with the blue glow of the new drink, never showing the bottle in an illuminated environment. The billboard will show the bottle's blue silhouette on a black background.
The tag line will be "Try something new... Go Blue!". The name will not be revealed until Stage Two.""",
'Nuka Cola - Stage Two': """Stage Two of the Nuka-Cola Quantum marketing will include: 2 (two) 30 (thirty)-second television commercials, 4 (four) 15 (fifteen)-second radio commercials and a highway billboard campaign.
In this stage, the name "Quantum" will be revealed and the bottle shown in full view. We will emphasize the drink's new energy content and flavor.
The tag line will be "Take the leap... enjoy a Quantum!" """,
'Nuka Cola - Stage Three': """Stage Three of the Nuka-Cola Quantum marketing will include: 4 (four) 30 (thirty)-second television commercials, 4 (four) 15 (fifteen)-second radio commercials and a highway billboard campaign.
In this final stage we will aggressively compare the drink to other competitors and show their inferiority using hired actors at "taste tests". The actors will read pre-written scripts approved by our department. The text should give an authentic "on the spot" impression but still clearly point out Quantum's strengths.
The tag line will remain: "Take the leap... enjoy a Quantum!" """,
}
LOG_NAMES = list(LOGS.keys())
LOG_NAMES.extend(["Return"])
LOG_RET_ID = len(LOG_NAMES) - 1

View file

@ -1,6 +1,11 @@
import curses
import time
import sys
from pathlib import Path as _Path
from playsound import playsound as _play
from threading import Thread
from time import sleep
LETTER_PAUSE = 5
@ -12,16 +17,29 @@ HIDDEN_MASK = '*'
NEWLINE = 10
DELETE = 127
DELETE = 330
def slowWrite(window, text, pause = LETTER_PAUSE):
BACKSPACE = 263
_playing = False
_soundQueue = []
global _queueRunning
_queueRunning = False
def slowWrite(window, text, pause = LETTER_PAUSE, fake_user = False):
"""
wrapper for curses.addstr() which writes the text slowely
"""
if not fake_user:
addSound("beep")
for i in range(len(text)):
window.addstr(text[i])
window.refresh()
curses.napms(pause)
if fake_user:
_playSound("keyenter", True)
def upperInput(window, hidden = False, can_newline = True):
"""
@ -39,8 +57,9 @@ def upperInput(window, hidden = False, can_newline = True):
if inchar > 96 and inchar < 123:
inchar -= 32
# deal with backspace
if inchar == DELETE:
if inchar in [DELETE, BACKSPACE]:
if len(instr) > 0:
#addSound("keyenter")
instr = instr[:-1]
cur = window.getyx()
window.move(cur[0], cur[1] - 1)
@ -51,12 +70,14 @@ def upperInput(window, hidden = False, can_newline = True):
continue
# output the character
elif inchar != NEWLINE:
#addSound("keyenter")
instr += chr(inchar)
if hidden:
window.addch(HIDDEN_MASK)
else:
window.addch(inchar)
elif can_newline:
#addSound("keyenter")
window.addch(NEWLINE)
return instr
@ -67,3 +88,73 @@ def centeredWrite(window, text, pause = LETTER_PAUSE):
width = window.getmaxyx()[1]
window.move(window.getyx()[0], int(width / 2 - len(text) / 2))
slowWrite(window, text, pause)
def _soundCheck():
"""
Internal use - Checks if the user explicity disabled sound or not
"""
return '--no-sound' not in sys.argv
def _playSound(file, block = False):
"""
Internal use - plays a specific sound from the current directory
"""
if _soundCheck():
_play(str(_Path.cwd() / f'audio/{file}.wav'), block)
def _playQueue():
"""
Internal use - play sounds from a queue
"""
global _queueRunning
global _soundQueue
if _queueRunning:
return
_queueRunning = True
while 1:
if len(_soundQueue) > 0:
_playSound(_soundQueue[0], True)
_soundQueue.pop(0)
else:
sleep(0.02)
def isQueueEmpty():
"""
Check if the sound queue is empty
"""
return len(_soundQueue) == 0
def soundTest():
addSound("beep")
addSound("beep")
addSound("keyenter")
addSound("keyenter")
addSound("wrongpass")
addSound("wrongpass")
addSound("correctpass")
addSound("correctpass")
addSound("poweron")
addSound("poweron")
addSound("poweroff")
addSound("poweroff")
global _soundQueue
while not isQueueEmpty():
sleep(0.2)
def addSound(file):
"""
Add sounds to the queue
"""
global _soundQueue
_soundQueue.extend([file])
_queueMgr = Thread(target=_playQueue)
_queueMgr.daemon = True
_queueMgr.start()

View file

@ -2,8 +2,7 @@ import curses
import random
import time
import os
from fallout_functions import slowWrite
from fallout_functions import upperInput
from fallout_functions import slowWrite, upperInput, addSound
################## text strings ######################
@ -23,7 +22,7 @@ LOGIN_ATTEMPTS = 4
HEADER_LINES = 5
# amount of time to pause after correct password input
LOGIN_PAUSE = 3000
LOGIN_PAUSE = 3
# starting number for hex generation
START_HEX = 0xf650
@ -212,6 +211,8 @@ def userInput(scr, passwords):
# user got password right
if guess.upper() == pwd.upper():
addSound("correctpass")
inputPad.addstr('>Exact match!\n')
inputPad.addstr('>Please wait\n')
inputPad.addstr('>while system\n')
@ -219,7 +220,7 @@ def userInput(scr, passwords):
moveInput(scr, inputPad)
curses.napms(LOGIN_PAUSE)
time.sleep(LOGIN_PAUSE)
return pwd
# wrong password
@ -233,6 +234,7 @@ def userInput(scr, passwords):
except IndexError:
pass # user did not enter enough letters
addSound("wrongpass")
inputPad.addstr('>Entry denied\n')
inputPad.addstr('>' + str(matched) + '/' + str(pwdLen) +
' correct.\n')

View file

@ -47,7 +47,7 @@ def runLogin(scr, hardMode, username, password):
# input is entered for them
slowWrite(scr, '> ')
curses.napms(INPUT_PAUSE)
slowWrite(scr, ENTRY + username.upper() + '\n', TYPE_DELAY)
slowWrite(scr, ENTRY + username.upper() + '\n', TYPE_DELAY, True)
slowWrite(scr, '\n' + PASSWORD_PROMPT + '\n\n')
@ -65,7 +65,7 @@ def runLogin(scr, hardMode, username, password):
slowWrite(scr, '> ')
curses.napms(INPUT_PAUSE)
password_stars = HIDDEN_MASK * len(password)
slowWrite(scr, password_stars + '\n', TYPE_DELAY)
slowWrite(scr, password_stars + '\n', TYPE_DELAY, True)
curses.napms(500)

View file

@ -1,33 +1,10 @@
import curses
from fallout_functions import slowWrite
from fallout_functions import centeredWrite
from fallout_functions import NEWLINE
####################### text strings ########################
CENTERED_HEADERS = (
'ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM',
'COPYRIGHT 2075-2077 ROBCO INDUSTRIES',
'-SERVER 6-',
''
)
OTHER_HEADERS = (
'\tSoftLock Solutions, Inc',
'"Your Security is Our Security"',
'>\\ Welcome, USER',
''
)
SELECTIONS = (
'Disengage Lock',
'Deactivate Turrets',
'Read Log'
)
from time import sleep
from fallout_functions import slowWrite, centeredWrite, NEWLINE, addSound
###################### Functions ############################
def makeSelection(scr):
def makeSelection(scr, SELECTIONS, MSGS):
"""
ALlow the user to select an option
Returns the line number of the users selection starting at 0
@ -37,7 +14,7 @@ def makeSelection(scr):
selection_count = len(SELECTIONS)
selection_start_y = scr.getyx()[0]
width = scr.getmaxyx()[1]
while inchar != NEWLINE:
# move to start of selections and hightlight current selection
scr.move(selection_start_y, 0)
@ -46,7 +23,7 @@ def makeSelection(scr):
whole_line = '> ' + SELECTIONS[line]
space = width - len(whole_line) % width
whole_line += ' ' * space
if line == selection:
scr.addstr(whole_line, curses.A_REVERSE)
else:
@ -59,13 +36,23 @@ def makeSelection(scr):
# move up and down
if inchar == curses.KEY_UP and selection > 0:
selection -= 1
addSound("keyenter")
elif inchar == curses.KEY_DOWN and selection < selection_count - 1:
selection += 1
addSound("keyenter")
if MSGS and MSGS[selection]:
whole_line = '> ' + MSGS[selection]
space = width - len(whole_line) % width
whole_line += ' ' * space
scr.addstr(' ' * width)
scr.addstr(whole_line)
scr.refresh()
sleep(2)
addSound("keyenter")
return selection
def runSelection(scr):
def runSelection(scr, CENTERED_HEADERS, OTHER_HEADERS, OPTIONS, MESSAGES):
"""
Print the selections and allow the user to select one
"""
@ -87,11 +74,11 @@ def runSelection(scr):
scr.addch(curses.ACS_BSBS)
scr.refresh()
return makeSelection(scr)
return makeSelection(scr, OPTIONS, MESSAGES)
def beginSelection():
def beginSelection(center, other, options, messages = []):
"""
Initialize curses and start the boot process
"""
res = curses.wrapper(runSelection)
res = curses.wrapper(runSelection, center, other, options, messages)
return res

0
fallout_things.py Normal file
View file

33
play-test.py Normal file
View file

@ -0,0 +1,33 @@
"""PyAudio Example: Play a wave file."""
import wave
import sys
import pyaudio
CHUNK = 1024
if len(sys.argv) < 2:
print(f'Plays a wave file. Usage: {sys.argv[0]} filename.wav')
sys.exit(-1)
with wave.open(sys.argv[1], 'rb') as wf:
# Instantiate PyAudio and initialize PortAudio system resources (1)
p = pyaudio.PyAudio()
# Open stream (2)
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
# Play samples from the wave file (3)
while len(data := wf.readframes(CHUNK)): # Requires Python 3.8+ for :=
stream.write(data)
# Close stream (4)
stream.close()
# Release PortAudio system resources (5)
p.terminate()