Compare commits
2 commits
main
...
tab_suppor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f6e5fdea0 | ||
|
|
6ae41eaffa |
51 changed files with 461 additions and 11836 deletions
33
.github/workflows/build.yml
vendored
33
.github/workflows/build.yml
vendored
|
|
@ -1,33 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2025 Tim Cocks, written for Adafruit Industries
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
name: Validate Build
|
|
||||||
|
|
||||||
on: [pull_request, push]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up requested Python version
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: 3.12
|
|
||||||
- name: Versions
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python3 --version
|
|
||||||
- name: Checkout Current Repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
show-progress: false
|
|
||||||
- name: Install reqs
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pip install -r requirements.txt
|
|
||||||
- name: Build Fruit Jam OS
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python build.py
|
|
||||||
76
.github/workflows/daily_release_check.yml
vendored
76
.github/workflows/daily_release_check.yml
vendored
|
|
@ -1,76 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2025 Tim Cocks, written for Adafruit Industries
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
name: Daily Release Check
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: 15 8 * * *
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release_check:
|
|
||||||
if: github.repository_owner == 'adafruit'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
release_created: ${{ steps.check_release.outputs.release_created }}
|
|
||||||
assets_upload_url: ${{ steps.check_release.outputs.assets_upload_url }}
|
|
||||||
steps:
|
|
||||||
- name: Set up requested Python version
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: 3.12
|
|
||||||
- name: Versions
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python3 --version
|
|
||||||
- name: Checkout Current Repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
show-progress: false
|
|
||||||
- name: Install reqs
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pip install -r requirements.txt
|
|
||||||
- name: Create Release If Needed
|
|
||||||
id: check_release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python release_updater.py make_release
|
|
||||||
|
|
||||||
upload_release_assets:
|
|
||||||
needs: release_check
|
|
||||||
if: github.repository_owner == 'adafruit' && needs.release_check.outputs.release_created == 'true'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up requested Python version
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: 3.12
|
|
||||||
- name: Versions
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python3 --version
|
|
||||||
- name: Checkout Current Repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
show-progress: false
|
|
||||||
- name: Install reqs
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pip install -r requirements.txt
|
|
||||||
- name: Build assets
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python build.py
|
|
||||||
- name: Upload Release Assets
|
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
|
||||||
with:
|
|
||||||
asset_path: "dist/*"
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
upload_url: ${{ needs.release_check.outputs.assets_upload_url }}
|
|
||||||
42
.github/workflows/release_gh.yml
vendored
42
.github/workflows/release_gh.yml
vendored
|
|
@ -1,42 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2025 Tim Cocks, written for Adafruit Industries
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
name: GitHub Release Actions
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
upload-release-assets:
|
|
||||||
if: github.repository_owner == 'adafruit'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up requested Python version
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: 3.12
|
|
||||||
- name: Versions
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python3 --version
|
|
||||||
- name: Checkout Current Repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
show-progress: false
|
|
||||||
- name: Install reqs
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pip install -r requirements.txt
|
|
||||||
- name: Build assets
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python build.py
|
|
||||||
- name: Upload Release Assets
|
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
|
||||||
with:
|
|
||||||
asset_path: "dist/*"
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,3 +1,2 @@
|
||||||
dist
|
dist
|
||||||
latest_dl
|
|
||||||
Adafruit_Learning_System_Guides
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
# Fruit Jam OS
|
|
||||||
128
build.py
128
build.py
|
|
@ -1,25 +1,19 @@
|
||||||
from datetime import datetime
|
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
import zipfile
|
import zipfile
|
||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import requests
|
||||||
from circup.commands import main as circup_cli
|
from circup.commands import main as circup_cli
|
||||||
|
|
||||||
|
LEARN_PROJECT_URLS = [
|
||||||
# each path is a tuple that contains:
|
"https://cdn-learn.adafruit.com/downloads/zip/3194974/Metro/Metro_RP2350_Snake.zip?timestamp={}",
|
||||||
# (path within learn repo, directory name to use inside of apps/)
|
"https://cdn-learn.adafruit.com/downloads/zip/3195762/Metro/Metro_RP2350_Memory/memory_game.zip?timestamp={}",
|
||||||
LEARN_PROJECT_PATHS = [
|
"https://cdn-learn.adafruit.com/downloads/zip/3195805/Metro/Metro_RP2350_CircuitPython_Matrix.zip?timestamp={}",
|
||||||
("Metro/Metro_RP2350_Snake/","Metro_RP2350_Snake"),
|
"https://cdn-learn.adafruit.com/downloads/zip/3194658/Metro/Metro_RP2350_FlappyNyanCat.zip?timestamp={}",
|
||||||
("Metro/Metro_RP2350_Memory/memory_game/", "Metro_RP2350_Memory"),
|
"https://cdn-learn.adafruit.com/downloads/zip/3196927/Metro/Metro_RP2350_Match3/match3_game.zip?timestamp={}",
|
||||||
("Metro/Metro_RP2350_CircuitPython_Matrix/", "Metro_RP2350_CircuitPython_Matrix"),
|
"https://cdn-learn.adafruit.com/downloads/zip/3194422/Metro/Metro_RP2350_Breakout.zip?timestamp={}",
|
||||||
("Metro/Metro_RP2350_FlappyNyanCat/", "Metro_RP2350_FlappyNyanCat"),
|
"https://cdn-learn.adafruit.com/downloads/zip/3196755/Metro/Metro_RP2350_Chips_Challenge.zip?timestamp={}",
|
||||||
("Metro/Metro_RP2350_Match3/match3_game/", "Metro_RP2350_Match3"),
|
|
||||||
("Metro/Metro_RP2350_Breakout/", "Metro_RP2350_Breakout"),
|
|
||||||
("Metro/Metro_RP2350_Chips_Challenge/", "Metro_RP2350_Chips_Challenge"),
|
|
||||||
("Metro/Metro_RP2350_Minesweeper/", "Metro_RP2350_Minesweeper"),
|
|
||||||
("Fruit_Jam/Larsio_Paint_Music/", "Larsio_Paint_Music"),
|
|
||||||
("Fruit_Jam/Fruit_Jam_IRC_Client/", "Fruit_Jam_IRC_Client"),
|
|
||||||
("Fruit_Jam/Fruit_Jam_PyPaint/", "Fruit_Jam_PyPaint"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir: Path, output_dir: Path):
|
def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir: Path, output_dir: Path):
|
||||||
|
|
@ -38,8 +32,6 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
|
||||||
try:
|
try:
|
||||||
# Copy src contents
|
# Copy src contents
|
||||||
shutil.copytree(src_dir, temp_dir, dirs_exist_ok=True)
|
shutil.copytree(src_dir, temp_dir, dirs_exist_ok=True)
|
||||||
# remove empty __init__.py file
|
|
||||||
os.remove(temp_dir / "__init__.py")
|
|
||||||
|
|
||||||
# Create fonts directory and copy the specific font
|
# Create fonts directory and copy the specific font
|
||||||
fonts_dir = temp_dir / "fonts"
|
fonts_dir = temp_dir / "fonts"
|
||||||
|
|
@ -49,30 +41,83 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
|
||||||
# Extract learn-projects contents into apps directory
|
# Extract learn-projects contents into apps directory
|
||||||
apps_dir = temp_dir / "apps"
|
apps_dir = temp_dir / "apps"
|
||||||
apps_dir.mkdir(parents=True, exist_ok=True)
|
apps_dir.mkdir(parents=True, exist_ok=True)
|
||||||
# copy learn apps
|
for zip_path in learn_projects_dir.glob("*.zip"):
|
||||||
for learn_app_path, dir_name in LEARN_PROJECT_PATHS:
|
# Create app-specific directory using zip name without extension
|
||||||
shutil.copytree(f"Adafruit_Learning_System_Guides/{learn_app_path}", apps_dir / dir_name, dirs_exist_ok=True)
|
app_name = zip_path.stem
|
||||||
|
app_dir = apps_dir / app_name
|
||||||
|
app_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Extract zip contents and process them
|
||||||
|
with zipfile.ZipFile(zip_path, 'r') as zf:
|
||||||
|
# Find the directory containing code.py
|
||||||
|
code_dir = None
|
||||||
|
for path in zf.namelist():
|
||||||
|
if path.endswith('/code.py'):
|
||||||
|
code_dir = str(Path(path).parent) + '/'
|
||||||
|
break
|
||||||
|
|
||||||
|
if not code_dir:
|
||||||
|
print(f"Warning: No code.py found in {zip_path}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Extract files from the code.py directory to app directory
|
||||||
|
for path in zf.namelist():
|
||||||
|
if path.startswith(code_dir):
|
||||||
|
# Skip the lib directory as we'll handle it separately
|
||||||
|
if 'lib/' in path:
|
||||||
|
continue
|
||||||
|
if path.endswith("/"):
|
||||||
|
# skip directories, they will get created by
|
||||||
|
# mkdir(parents=True) below
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get the relative path from code_dir
|
||||||
|
rel_path = path[len(code_dir):]
|
||||||
|
if rel_path:
|
||||||
|
# Extract the file
|
||||||
|
source = zf.open(path)
|
||||||
|
target = app_dir / rel_path
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(target, 'wb') as f:
|
||||||
|
f.write(source.read())
|
||||||
|
|
||||||
|
# Handle lib directory specially - move to root
|
||||||
|
for path in zf.namelist():
|
||||||
|
if '/lib/' in path:
|
||||||
|
# Get the part of the path after 'lib/'
|
||||||
|
lib_index = path.index('/lib/') + 5 # skip past '/lib/'
|
||||||
|
rel_path = path[lib_index:]
|
||||||
|
|
||||||
|
# Skip directory entries
|
||||||
|
if not rel_path or path.endswith('/'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Extract the file to root lib directory
|
||||||
|
source = zf.open(path)
|
||||||
|
target = temp_dir / 'lib' / rel_path
|
||||||
|
# Ensure parent directory exists
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
# Write the file
|
||||||
|
with open(target, 'wb') as f:
|
||||||
|
f.write(source.read())
|
||||||
|
|
||||||
# copy builtin apps
|
# copy builtin apps
|
||||||
shutil.copytree("builtin_apps", apps_dir, dirs_exist_ok=True)
|
shutil.copytree("builtin_apps", apps_dir, dirs_exist_ok=True)
|
||||||
shutil.copyfile("mock_boot_out.txt", temp_dir / "boot_out.txt")
|
shutil.copyfile("mock_boot_out.txt", temp_dir / "boot_out.txt")
|
||||||
|
for builtin_app_dir in os.listdir("builtin_apps"):
|
||||||
# install launcher required libs
|
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"apps/{builtin_app_dir}/code.py"],
|
||||||
circup_cli(["--path", temp_dir, "install", "--auto"],
|
|
||||||
standalone_mode=False)
|
|
||||||
|
|
||||||
# install apps required libs
|
|
||||||
for app_dir in os.listdir(apps_dir):
|
|
||||||
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"apps/{app_dir}/code.py"],
|
|
||||||
standalone_mode=False)
|
standalone_mode=False)
|
||||||
|
|
||||||
|
# install reqs for launcher and boot_animation
|
||||||
|
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"code.py"], standalone_mode=False)
|
||||||
|
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"boot_animation.py"], standalone_mode=False)
|
||||||
|
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"boot.py"], standalone_mode=False)
|
||||||
|
|
||||||
os.remove(temp_dir / "boot_out.txt")
|
os.remove(temp_dir / "boot_out.txt")
|
||||||
# Create the final zip file
|
# Create the final zip file
|
||||||
with zipfile.ZipFile(output_zip, 'w', zipfile.ZIP_DEFLATED) as zf:
|
with zipfile.ZipFile(output_zip, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||||||
for file_path in temp_dir.rglob("*"):
|
for file_path in temp_dir.rglob("*"):
|
||||||
if file_path.is_file():
|
if file_path.is_file():
|
||||||
modification_time = datetime(2000, 1, 1, 0, 0, 0)
|
|
||||||
modification_timestamp = modification_time.timestamp()
|
|
||||||
os.utime(file_path, (modification_timestamp, modification_timestamp))
|
|
||||||
arcname = file_path.relative_to(temp_dir)
|
arcname = file_path.relative_to(temp_dir)
|
||||||
zf.write(file_path, arcname)
|
zf.write(file_path, arcname)
|
||||||
|
|
||||||
|
|
@ -84,12 +129,13 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
|
||||||
|
|
||||||
|
|
||||||
def download_learn_projects():
|
def download_learn_projects():
|
||||||
try:
|
for url in LEARN_PROJECT_URLS:
|
||||||
shutil.rmtree("Adafruit_Learning_System_Guides/")
|
response = requests.get(url.format(int(time.time())), allow_redirects=True)
|
||||||
except FileNotFoundError:
|
resp_url = response.url
|
||||||
pass
|
#print(resp_url)
|
||||||
|
filename = resp_url.split("/")[-1].split("?")[0]
|
||||||
os.system("git clone https://github.com/adafruit/Adafruit_Learning_System_Guides.git")
|
with open(f"learn-projects/{filename}", 'wb') as f:
|
||||||
|
f.write(response.content)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
@ -105,11 +151,7 @@ def main():
|
||||||
src_dir = root_dir / "src"
|
src_dir = root_dir / "src"
|
||||||
learn_projects_dir = root_dir / "learn-projects"
|
learn_projects_dir = root_dir / "learn-projects"
|
||||||
output_dir = root_dir / "dist"
|
output_dir = root_dir / "dist"
|
||||||
|
|
||||||
# delete output dir if it exists
|
|
||||||
if output_dir.exists():
|
|
||||||
shutil.rmtree(output_dir)
|
|
||||||
|
|
||||||
# Create output directory
|
# Create output directory
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,674 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
|
||||||
or can get the source code. And you must show them these terms so they
|
|
||||||
know their rights.
|
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
|
||||||
that there is no warranty for this free software. For both users' and
|
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
|
||||||
changed, so that their problems will not be attributed erroneously to
|
|
||||||
authors of previous versions.
|
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the special requirements of the GNU Affero General Public License,
|
|
||||||
section 13, concerning interaction through a network will apply to the
|
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
|
||||||
notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
Changes made to https://github.com/richpl/PyBasic on 8/6/2025 to support CircuitPython and Fruit-Jam-OS.
|
|
||||||
|
|
||||||
1) interpreter.py (modified printing of trapped exceptions for CircuitPython):
|
|
||||||
|
|
||||||
Added the following import (line 30):
|
|
||||||
from traceback import print_exception
|
|
||||||
|
|
||||||
Replaced exception print (line 130):
|
|
||||||
Orig: print(e, file=stderr, flush=True)
|
|
||||||
New: print_exception(e,e,e.__traceback__ if hasattr(e,'__traceback__') else None)
|
|
||||||
|
|
||||||
2) program.py (set the default directory to the same directory a program is loaded from):
|
|
||||||
|
|
||||||
Added the following import (line 28):
|
|
||||||
import os
|
|
||||||
|
|
||||||
Added command to set current directory to folder loaded program is loaded from (line 236-239):
|
|
||||||
if file.rfind('/') == 0:
|
|
||||||
os.chdir('/')
|
|
||||||
elif file.rfind('/') != -1:
|
|
||||||
os.chdir(file[:file.rfind('/')])
|
|
||||||
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.1 KiB |
|
|
@ -1,7 +0,0 @@
|
||||||
# Launches the PyBasic interpreter
|
|
||||||
#
|
|
||||||
# See the "Pybasic changes.txt" file for a list of difference from
|
|
||||||
# the original https://github.com/richpl/PyBasic
|
|
||||||
#
|
|
||||||
import interpreter
|
|
||||||
interpreter.main()
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,200 +0,0 @@
|
||||||
#! /usr/bin/python
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
"""Class to represent a token for the BASIC
|
|
||||||
programming language. A token consists of
|
|
||||||
three items:
|
|
||||||
|
|
||||||
column Column in which token starts
|
|
||||||
category Category of the token
|
|
||||||
lexeme Token in string form
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class BASICToken:
|
|
||||||
|
|
||||||
"""BASICToken categories"""
|
|
||||||
|
|
||||||
EOF = 0 # End of file
|
|
||||||
LET = 1 # LET keyword
|
|
||||||
LIST = 2 # LIST command
|
|
||||||
PRINT = 3 # PRINT command
|
|
||||||
RUN = 4 # RUN command
|
|
||||||
FOR = 5 # FOR keyword
|
|
||||||
NEXT = 6 # NEXT keyword
|
|
||||||
IF = 7 # IF keyword
|
|
||||||
THEN = 8 # THEN keyword
|
|
||||||
ELSE = 9 # ELSE keyword
|
|
||||||
ASSIGNOP = 10 # '='
|
|
||||||
LEFTPAREN = 11 # '('
|
|
||||||
RIGHTPAREN = 12 # ')'
|
|
||||||
PLUS = 13 # '+'
|
|
||||||
MINUS = 14 # '-'
|
|
||||||
TIMES = 15 # '*'
|
|
||||||
DIVIDE = 16 # '/'
|
|
||||||
NEWLINE = 17 # End of line
|
|
||||||
UNSIGNEDINT = 18 # Integer
|
|
||||||
NAME = 19 # Identifier that is not a keyword
|
|
||||||
EXIT = 20 # Used to quit the interpreter
|
|
||||||
DIM = 21 # DIM keyword
|
|
||||||
GREATER = 22 # '>'
|
|
||||||
LESSER = 23 # '<'
|
|
||||||
STEP = 24 # STEP keyword
|
|
||||||
GOTO = 25 # GOTO keyword
|
|
||||||
GOSUB = 26 # GOSUB keyword
|
|
||||||
INPUT = 27 # INPUT keyword
|
|
||||||
REM = 28 # REM keyword
|
|
||||||
RETURN = 29 # RETURN keyword
|
|
||||||
SAVE = 30 # SAVE command
|
|
||||||
LOAD = 31 # LOAD command
|
|
||||||
NOTEQUAL = 32 # '<>'
|
|
||||||
LESSEQUAL = 33 # '<='
|
|
||||||
GREATEQUAL = 34 # '>='
|
|
||||||
UNSIGNEDFLOAT = 35 # Floating point number
|
|
||||||
STRING = 36 # String values
|
|
||||||
TO = 37 # TO keyword
|
|
||||||
NEW = 38 # NEW command
|
|
||||||
EQUAL = 39 # '='
|
|
||||||
COMMA = 40 # ','
|
|
||||||
STOP = 41 # STOP keyword
|
|
||||||
COLON = 42 # ':'
|
|
||||||
ON = 43 # ON keyword
|
|
||||||
POW = 44 # Power function
|
|
||||||
SQR = 45 # Square root function
|
|
||||||
ABS = 46 # Absolute value function
|
|
||||||
DIM = 47 # DIM keyword
|
|
||||||
RANDOMIZE = 48 # RANDOMIZE keyword
|
|
||||||
RND = 49 # RND keyword
|
|
||||||
ATN = 50 # Arctangent function
|
|
||||||
COS = 51 # Cosine function
|
|
||||||
EXP = 52 # Exponential function
|
|
||||||
LOG = 53 # Natural logarithm function
|
|
||||||
SIN = 54 # Sine function
|
|
||||||
TAN = 55 # Tangent function
|
|
||||||
DATA = 56 # DATA keyword
|
|
||||||
READ = 57 # READ keyword
|
|
||||||
INT = 58 # INT function
|
|
||||||
CHR = 59 # CHR$ function
|
|
||||||
ASC = 60 # ASC function
|
|
||||||
STR = 61 # STR$ function
|
|
||||||
MID = 62 # MID$ function
|
|
||||||
MODULO = 63 # MODULO operator
|
|
||||||
TERNARY = 64 # TERNARY functions
|
|
||||||
VAL = 65 # VAL function
|
|
||||||
LEN = 66 # LEN function
|
|
||||||
UPPER = 67 # UPPER function
|
|
||||||
LOWER = 68 # LOWER function
|
|
||||||
ROUND = 69 # ROUND function
|
|
||||||
MAX = 70 # MAX function
|
|
||||||
MIN = 71 # MIN function
|
|
||||||
INSTR = 72 # INSTR function
|
|
||||||
AND = 73 # AND operator
|
|
||||||
OR = 74 # OR operator
|
|
||||||
NOT = 75 # NOT operator
|
|
||||||
PI = 76 # PI constant
|
|
||||||
RNDINT = 77 # RNDINT function
|
|
||||||
OPEN = 78 # OPEN keyword
|
|
||||||
HASH = 79 # "#"
|
|
||||||
CLOSE = 80 # CLOSE keyword
|
|
||||||
FSEEK = 81 # FSEEK keyword
|
|
||||||
RESTORE = 82 # RESTORE keyword
|
|
||||||
APPEND = 83 # APPEND keyword
|
|
||||||
OUTPUT = 84 # OUTPUT keyword
|
|
||||||
TAB = 85 # TAB function
|
|
||||||
SEMICOLON = 86 # SEMICOLON
|
|
||||||
LEFT = 87 # LEFT$ function
|
|
||||||
RIGHT = 88 # RIGHT$ function
|
|
||||||
|
|
||||||
# Displayable names for each token category
|
|
||||||
catnames = ['EOF', 'LET', 'LIST', 'PRINT', 'RUN',
|
|
||||||
'FOR', 'NEXT', 'IF', 'THEN', 'ELSE', 'ASSIGNOP',
|
|
||||||
'LEFTPAREN', 'RIGHTPAREN', 'PLUS', 'MINUS', 'TIMES',
|
|
||||||
'DIVIDE', 'NEWLINE', 'UNSIGNEDINT', 'NAME', 'EXIT',
|
|
||||||
'DIM', 'GREATER', 'LESSER', 'STEP', 'GOTO', 'GOSUB',
|
|
||||||
'INPUT', 'REM', 'RETURN', 'SAVE', 'LOAD',
|
|
||||||
'NOTEQUAL', 'LESSEQUAL', 'GREATEQUAL',
|
|
||||||
'UNSIGNEDFLOAT', 'STRING', 'TO', 'NEW', 'EQUAL',
|
|
||||||
'COMMA', 'STOP', 'COLON', 'ON', 'POW', 'SQR', 'ABS',
|
|
||||||
'DIM', 'RANDOMIZE', 'RND', 'ATN', 'COS', 'EXP',
|
|
||||||
'LOG', 'SIN', 'TAN', 'DATA', 'READ', 'INT',
|
|
||||||
'CHR', 'ASC', 'STR', 'MID', 'MODULO', 'TERNARY',
|
|
||||||
'VAL', 'LEN', 'UPPER', 'LOWER', 'ROUND',
|
|
||||||
'MAX', 'MIN', 'INSTR', 'AND', 'OR', 'NOT', 'PI',
|
|
||||||
'RNDINT', 'OPEN', 'HASH', 'CLOSE', 'FSEEK', 'APPEND',
|
|
||||||
'OUTPUT', 'RESTORE', 'RNDINT', 'TAB', 'SEMICOLON',
|
|
||||||
'LEFT', 'RIGHT']
|
|
||||||
|
|
||||||
smalltokens = {'=': ASSIGNOP, '(': LEFTPAREN, ')': RIGHTPAREN,
|
|
||||||
'+': PLUS, '-': MINUS, '*': TIMES, '/': DIVIDE,
|
|
||||||
'\n': NEWLINE, '<': LESSER,
|
|
||||||
'>': GREATER, '<>': NOTEQUAL,
|
|
||||||
'<=': LESSEQUAL, '>=': GREATEQUAL, ',': COMMA,
|
|
||||||
':': COLON, '%': MODULO, '!=': NOTEQUAL, '#': HASH,
|
|
||||||
';': SEMICOLON}
|
|
||||||
|
|
||||||
|
|
||||||
# Dictionary of BASIC reserved words
|
|
||||||
keywords = {'LET': LET, 'LIST': LIST, 'PRINT': PRINT,
|
|
||||||
'FOR': FOR, 'RUN': RUN, 'NEXT': NEXT,
|
|
||||||
'IF': IF, 'THEN': THEN, 'ELSE': ELSE,
|
|
||||||
'EXIT': EXIT, 'DIM': DIM, 'STEP': STEP,
|
|
||||||
'GOTO': GOTO, 'GOSUB': GOSUB,
|
|
||||||
'INPUT': INPUT, 'REM': REM, 'RETURN': RETURN,
|
|
||||||
'SAVE': SAVE, 'LOAD': LOAD, 'NEW': NEW,
|
|
||||||
'STOP': STOP, 'TO': TO, 'ON':ON, 'POW': POW,
|
|
||||||
'SQR': SQR, 'ABS': ABS,
|
|
||||||
'RANDOMIZE': RANDOMIZE, 'RND': RND,
|
|
||||||
'ATN': ATN, 'COS': COS, 'EXP': EXP,
|
|
||||||
'LOG': LOG, 'SIN': SIN, 'TAN': TAN,
|
|
||||||
'DATA': DATA, 'READ': READ, 'INT': INT,
|
|
||||||
'CHR$': CHR, 'ASC': ASC, 'STR$': STR,
|
|
||||||
'MID$': MID, 'MOD': MODULO,
|
|
||||||
'IF$': TERNARY, 'IFF': TERNARY,
|
|
||||||
'VAL': VAL, 'LEN': LEN,
|
|
||||||
'UPPER$': UPPER, 'LOWER$': LOWER,
|
|
||||||
'ROUND': ROUND, 'MAX': MAX, 'MIN': MIN,
|
|
||||||
'INSTR': INSTR, 'END': STOP,
|
|
||||||
'AND': AND, 'OR': OR, 'NOT': NOT,
|
|
||||||
'PI': PI, 'RNDINT': RNDINT, 'OPEN': OPEN,
|
|
||||||
'CLOSE': CLOSE, 'FSEEK': FSEEK,
|
|
||||||
'APPEND': APPEND, 'OUTPUT':OUTPUT,
|
|
||||||
'RESTORE': RESTORE, 'TAB': TAB,
|
|
||||||
'LEFT$': LEFT, 'RIGHT$': RIGHT}
|
|
||||||
|
|
||||||
|
|
||||||
# Functions
|
|
||||||
functions = {ABS, ATN, COS, EXP, INT, LOG, POW, RND, SIN, SQR, TAN,
|
|
||||||
CHR, ASC, MID, TERNARY, STR, VAL, LEN, UPPER, LOWER,
|
|
||||||
ROUND, MAX, MIN, INSTR, PI, RNDINT, TAB, LEFT, RIGHT}
|
|
||||||
|
|
||||||
def __init__(self, column, category, lexeme):
|
|
||||||
|
|
||||||
self.column = column # Column in which token starts
|
|
||||||
self.category = category # Category of the token
|
|
||||||
self.lexeme = lexeme # Token in string form
|
|
||||||
|
|
||||||
def pretty_print(self):
|
|
||||||
"""Pretty prints the token
|
|
||||||
|
|
||||||
"""
|
|
||||||
print('Column:', self.column,
|
|
||||||
'Category:', self.catnames[self.category],
|
|
||||||
'Lexeme:', self.lexeme)
|
|
||||||
|
|
||||||
def print_lexeme(self):
|
|
||||||
print(self.lexeme, end=' ')
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
from supervisor import reload
|
|
||||||
import interpreter
|
|
||||||
interpreter.main()
|
|
||||||
reload()
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
You're in the forest.
|
|
||||||
You're in the forest.
|
|
||||||
You're in the forest.
|
|
||||||
You're in the forest.
|
|
||||||
You're at the hill in the road.
|
|
||||||
You're at the end of the road again.
|
|
||||||
You're inside the Building.
|
|
||||||
You're in the valley.
|
|
||||||
You're at slit in the streambed.
|
|
||||||
You're directly above a grate in a dry streambed.
|
|
||||||
You're below the grate.
|
|
||||||
You're in the cobble crawl.
|
|
||||||
You're in the debris room.
|
|
||||||
You are in an awkward sloping east/west canyon.
|
|
||||||
You're in the bird chamber.
|
|
||||||
You're at the top of the small pit.
|
|
||||||
You're in the Hall of Mists.
|
|
||||||
You're in the nugget of gold room.
|
|
||||||
You're on the east bank of the fissure.
|
|
||||||
You are on the west side of the fissure in the Hall of Mists.
|
|
||||||
You're at west end of the Hall of Mists.
|
|
||||||
You're in the Hall of the Mountain King.
|
|
||||||
You are in the south side chamber.
|
|
||||||
You are in the west side chamber of the Hall of the Mountain King.
|
|
||||||
You are at a N/S passage at a hole in the floor.
|
|
||||||
You're at Y2 .
|
|
||||||
You're at the window near the pit.
|
|
||||||
The passage here is blocked by a recent cave-in.
|
|
||||||
You're at the east end of the Long Hall.
|
|
||||||
You're at west end of the Long Hall.
|
|
||||||
You are at a crossover of a high N/S passage and a low E/W one.
|
|
||||||
Dead end
|
|
||||||
You are in a dirty broken passage.
|
|
||||||
You're at the top of the small pit.
|
|
||||||
You are in a little pit which has a stream flowing through it.
|
|
||||||
You're in the dusty rock room.
|
|
||||||
You're at a complex junction.
|
|
||||||
You're in the anteroom.
|
|
||||||
You are at Witt's end. Passages lead off in *all* directions.
|
|
||||||
You're in the shell room.
|
|
||||||
You're in the arched hall.
|
|
||||||
You're in a long sloping corridor with ragged sharp walls.
|
|
||||||
You are in a cul-de-sac about eight feet across. How's your french?
|
|
||||||
You are in bedquilt, a long east/west passage with holes everywhere.
|
|
||||||
You're in the swiss cheese room.
|
|
||||||
You're in the soft room.
|
|
||||||
You're at the east end of the Twopit room.
|
|
||||||
You're at the west end of the Twopit room.
|
|
||||||
You're in the east pit.
|
|
||||||
You're in the west pit.
|
|
||||||
You're in the slab room.
|
|
||||||
You're in the Oriental room.
|
|
||||||
You are in a large low room.
|
|
||||||
You're in a sloping corridor.
|
|
||||||
Dead end crawl.
|
|
||||||
You're in the misty cavern.
|
|
||||||
You're in the alcove.
|
|
||||||
You're in the Plover room.
|
|
||||||
You're in the dark-room.
|
|
||||||
You're on the SW side of the chasm.
|
|
||||||
You're on the NE side of the chasm.
|
|
||||||
You're in a corridor.
|
|
||||||
You're at the fork in the path.
|
|
||||||
You're in the limestone passage.
|
|
||||||
You're at a junction with warm walls.
|
|
||||||
You're in the chamber of boulders.
|
|
||||||
You're at a breath-taking view.
|
|
||||||
You're in front of the barren room.
|
|
||||||
You're in the barren room.
|
|
||||||
You're in a narrow corridor.
|
|
||||||
You're in the Giant room.
|
|
||||||
The passage here is blocked by a recent cave-in.
|
|
||||||
You are at one end of an immense north/south passage.
|
|
||||||
You're in the cavern with a waterfall
|
|
||||||
You're at a steep incline above a large room.
|
|
||||||
You are in a secret N/S canyon above a sizable passage.
|
|
||||||
You're at the top of the stalactite.
|
|
||||||
You're at a junction of three secret canyons.
|
|
||||||
You are in a secret N/S canyon above a large room.
|
|
||||||
You're in mirror canyon.
|
|
||||||
You're at a reservoir.
|
|
||||||
You are in a secret canyon which exits to the north and east.
|
|
||||||
You're in the secret E/W canyon above a tight canyon.
|
|
||||||
You are at a wide place in a very tight N/S canyon.
|
|
||||||
The canyon here becomes too tight to go on.
|
|
||||||
You are in a tall E/W canyon.
|
|
||||||
The canyon runs into a mass of boulders -- dead end.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are at a huge orange stalactite in the maze.
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
You are at a dead end.
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
There is a large sparking nugget of gold here!
|
|
||||||
There are bars of silver here!
|
|
||||||
There is precious jewelry here!
|
|
||||||
There are many coins here!
|
|
||||||
There are several diamonds here!
|
|
||||||
There is a delicate, precious ming vase here!
|
|
||||||
To one side lies a glistening Pearl!
|
|
||||||
There is a nest here, full of golden eggs!
|
|
||||||
There is a jewel-encrusted trident here!
|
|
||||||
There is an emerald the size of a plover's egg here!
|
|
||||||
There is a platinum pyramid here, eight inches on a side!
|
|
||||||
There is a golden chain here!
|
|
||||||
There are rare spices here!
|
|
||||||
There is a valuable persian rug here!
|
|
||||||
There is a chest here, full of various treasures!
|
|
||||||
There is a bottle of water here.
|
|
||||||
There is a small pool of oil here.
|
|
||||||
There is a brass lantern here.
|
|
||||||
There is a set of keys here.
|
|
||||||
There is food here.
|
|
||||||
There is a glass bottle here.
|
|
||||||
There is a small wicker cage here.
|
|
||||||
There is a 3-foot black rod here.
|
|
||||||
There is an enormous clam here with its shell tightly shut.
|
|
||||||
There is a recent issue of 'Spelunker Today' here.
|
|
||||||
There is a bear nearby.
|
|
||||||
There is a little axe here.
|
|
||||||
There is a purple velvet pillow here.
|
|
||||||
There are shards of pottery scattered about.
|
|
||||||
There is an enormous oyster here with its shell tightly shut.
|
|
||||||
There is a little bird here.
|
|
||||||
A burly troll stands in front of you.
|
|
||||||
A huge fierce green dragon bars the way!
|
|
||||||
A huge fierce green snake bars the way!
|
|
||||||
There is a threatening little dwarf in the room with you!
|
|
||||||
|
|
@ -1,583 +0,0 @@
|
||||||
#1
|
|
||||||
You can't move that way.
|
|
||||||
#2.1
|
|
||||||
Nothing happens.
|
|
||||||
#2.2
|
|
||||||
Nothing seems to happen.
|
|
||||||
#2.3
|
|
||||||
I don't think that had any affect on anything.
|
|
||||||
#2.4
|
|
||||||
I don't know how to apply that word here.
|
|
||||||
#2.5
|
|
||||||
That had little effect, if any at all.
|
|
||||||
#3
|
|
||||||
The mist is quite thick here, and the fissure is too wide to jump.
|
|
||||||
#4
|
|
||||||
You are at the bottom of the pit with a broken neck.
|
|
||||||
#5
|
|
||||||
The bottle is already filled!
|
|
||||||
#6
|
|
||||||
The bear eagerly wolfs down your food, after which he seems to calm
|
|
||||||
down considerably and even becomes rather friendly. burp
|
|
||||||
#7
|
|
||||||
The plant surges upwards, reaching halfway to the hole above you
|
|
||||||
#8
|
|
||||||
The plant grows explosively, almost filling the bottom of the pit.
|
|
||||||
#9
|
|
||||||
You overwatered the plant, you fool!
|
|
||||||
#10
|
|
||||||
The grate is locked.
|
|
||||||
#11
|
|
||||||
The grate is unlocked.
|
|
||||||
#12
|
|
||||||
The bear is quite ferocious, and will no doubt tear you to
|
|
||||||
shreds if you approach it!
|
|
||||||
#13
|
|
||||||
The chain is unlocked and the bear is free.
|
|
||||||
#14
|
|
||||||
A crystal bridge now spans the fissure.
|
|
||||||
#15
|
|
||||||
The bridge vanishes.
|
|
||||||
#16
|
|
||||||
It is beyond your power to do that.
|
|
||||||
#17
|
|
||||||
The clam opens momenntarily, and a glistening pearl falls out
|
|
||||||
and rolls away. Goodness, this must really have been an oyster.
|
|
||||||
(I never was any good at identifying bivalves, anyway.)
|
|
||||||
#18
|
|
||||||
I can't close that!
|
|
||||||
#19
|
|
||||||
The oil has freed up the hinges so that the door will now move,
|
|
||||||
although it requires some effort.
|
|
||||||
#20
|
|
||||||
I can't eat.
|
|
||||||
#21
|
|
||||||
How can I drink that?
|
|
||||||
#22
|
|
||||||
"Glug, glug, glug, Belch!"
|
|
||||||
#23
|
|
||||||
It doesn't want to eat anything (except maybe you!)
|
|
||||||
#24
|
|
||||||
You fool! Dwarves only eat coal! Now you've made him
|
|
||||||
*** REALLY MAD ****!
|
|
||||||
#25
|
|
||||||
Trolls are close relatives with the rocks and have skin as tough as
|
|
||||||
that of a rhinoceros. The troll fends off your blows effortlessly.
|
|
||||||
#26
|
|
||||||
The troll deftly catches the axe, examines it carefully, and tosses it
|
|
||||||
back, declaring, "Good workmanship, but it's not valuable enough."
|
|
||||||
#27
|
|
||||||
The troll catches your treasure and scurries away out of sight.
|
|
||||||
#28
|
|
||||||
The bear lumbers toward the troll, who lets out a startled shriek and
|
|
||||||
scurries away. The bear soon gives up the pursuit and wanders back.
|
|
||||||
#29
|
|
||||||
You attack a little dwarf, but he dodges out of the way.
|
|
||||||
#30
|
|
||||||
You killed a little dwarf. The body vanishes in a cloud of greasy
|
|
||||||
black smoke.
|
|
||||||
#31
|
|
||||||
There is a threatening little dwarf in the room with you!
|
|
||||||
#32
|
|
||||||
One sharp nasty knife is thrown at you!
|
|
||||||
#33
|
|
||||||
Out from the shadows behind you pounces a bearded pirate! "Har, har,"
|
|
||||||
he chortles, "I'll just take all this booty and hide it away with me
|
|
||||||
chest deep in the maze!" he snatches your treasure and vanishes into
|
|
||||||
the gloom.
|
|
||||||
#34
|
|
||||||
There are faint rustling noises from the darkness behind you.
|
|
||||||
#35
|
|
||||||
The grate is open.
|
|
||||||
#36
|
|
||||||
The grate is locked.
|
|
||||||
#37
|
|
||||||
The bird was unafraid when you entered, but as you approach it becomes
|
|
||||||
disturbed and you cannot catch it.
|
|
||||||
#38
|
|
||||||
The dome is unclimbable.
|
|
||||||
#39
|
|
||||||
A crystal bridge now spans the fissure.
|
|
||||||
#40
|
|
||||||
A huge green fierce snake bars the way! Hisssssss
|
|
||||||
#41
|
|
||||||
A hollow voice says "Plugh".
|
|
||||||
#42
|
|
||||||
The vase is now resting, delicately, on a velvet pillow.
|
|
||||||
#43
|
|
||||||
Crash! Tinkle! The ming vase shatters into worthless crockery.
|
|
||||||
#44
|
|
||||||
You fell into a pit and broke every bone in your body!
|
|
||||||
#45
|
|
||||||
It is now pitch dark. If you proceed you will likely fall into a pit.
|
|
||||||
#46
|
|
||||||
The nest of golden eggs has vanished!
|
|
||||||
#47
|
|
||||||
There is a tiny little plant in the pit, murmuring "water, water, ..."
|
|
||||||
#48
|
|
||||||
There is a 12-foot-tall beanstalk stretching up out of the pit,
|
|
||||||
bellowing "WATER!! WATER!!"
|
|
||||||
#49
|
|
||||||
There is a gigantic beanstalk stretching all the way up to the hole.
|
|
||||||
#50
|
|
||||||
You can't get by the snake. He hates your guts.
|
|
||||||
#51
|
|
||||||
The dragon has a rather "volatile" personality, and he will
|
|
||||||
probably incinerate you if you get any closer.
|
|
||||||
#52
|
|
||||||
You have crawled around in some little holes and wound up back in the
|
|
||||||
main passage.
|
|
||||||
#53
|
|
||||||
Something you're carrying won't fit through the tunnel with you.
|
|
||||||
#54
|
|
||||||
Your load is too heavy. You'd best take inventory and drop
|
|
||||||
something first.
|
|
||||||
#55
|
|
||||||
A burly troll stands by the bridge and insists you throw him a
|
|
||||||
treasure before you may cross.
|
|
||||||
#56
|
|
||||||
The troll pops from under the bridge and blocks your way.
|
|
||||||
#57
|
|
||||||
The way north is barred by a massive, rusty, iron door.
|
|
||||||
#58
|
|
||||||
The bear will bite off your hand. Besides, the chain is locked to the wall.
|
|
||||||
#59
|
|
||||||
It's rather difficult to move a twenty-ton dragon, considering
|
|
||||||
he is lying on the rug.
|
|
||||||
#60
|
|
||||||
The vase is now resting, delicately, on a velvet pillow.
|
|
||||||
#61.1
|
|
||||||
A valliant attempt!
|
|
||||||
#61.2
|
|
||||||
Nice try!
|
|
||||||
#61.3
|
|
||||||
A valliant attempt, but you're not that strong!
|
|
||||||
#61.4
|
|
||||||
Don't be silly!
|
|
||||||
#61.5
|
|
||||||
Do you have any idea on how to do that?
|
|
||||||
#62
|
|
||||||
A huge green fierce dragon blocks the way. The dragon is lying
|
|
||||||
on a persian rug!
|
|
||||||
#63
|
|
||||||
A burly troll stands beside the bridge, blocking your way.
|
|
||||||
#64
|
|
||||||
There is a ferocious cave bear eyeing you from the far end of the room!
|
|
||||||
#65
|
|
||||||
The bear is locked to the wall with a golden chain!
|
|
||||||
#66
|
|
||||||
There is a calm, friendly bear locked to the wall.
|
|
||||||
#67
|
|
||||||
You are being followed by a very large, tame bear.
|
|
||||||
#68
|
|
||||||
With what? Your bare hands?
|
|
||||||
#69
|
|
||||||
Congratulations! You have just vanquished a dragon with your bare hands
|
|
||||||
(hard to believe ain't it?).
|
|
||||||
#70
|
|
||||||
Attacking it is both dangerous and doesn't work.
|
|
||||||
#71
|
|
||||||
There is nothing here to attack.
|
|
||||||
#72
|
|
||||||
How can you do that to more than one thing at a time?
|
|
||||||
#73
|
|
||||||
Thank you, it was delicious!
|
|
||||||
#74
|
|
||||||
I see nothing special about that.
|
|
||||||
#75
|
|
||||||
Oh dear, you seem to have gotten yourself killed. I might be able to
|
|
||||||
help you out, but I've never really done this before. Do you want me
|
|
||||||
to try to reincarnate you?
|
|
||||||
#76
|
|
||||||
All right. But don't blame me if something goes wr......
|
|
||||||
--- POOF!! ---
|
|
||||||
You are engulfed in a cloud of orange smoke. Coughing and gasping,
|
|
||||||
you emerge from the smoke and find....
|
|
||||||
#77
|
|
||||||
You clumsy oaf, you've done it again! I don't know how long I can
|
|
||||||
keep this up. Do you want me to try reincarnating you again?
|
|
||||||
#78
|
|
||||||
Now you've really done it! I'm out of orange smoke! You don't expect
|
|
||||||
me to do a decent reincarnation without any orange smoke, do you?
|
|
||||||
Better luck next time!
|
|
||||||
#79
|
|
||||||
The nest of golden eggs has vanished!
|
|
||||||
#80
|
|
||||||
A little dwarf just walked around a corner, saw you, threw a little
|
|
||||||
axe at you which missed, cursed and ran away.
|
|
||||||
#81
|
|
||||||
The nest of golden eggs has re-appeared!
|
|
||||||
#200
|
|
||||||
You are in a forest, with trees all around you.
|
|
||||||
#205
|
|
||||||
You have walked up a hill, still in the forest. The road slopes back
|
|
||||||
down the other side of the hill. There is a building in the distance.
|
|
||||||
#206
|
|
||||||
You are standing at the end of a road before a small brick building.
|
|
||||||
Around you is a forest. A small stream flows out of the building and
|
|
||||||
down a gully.
|
|
||||||
#207
|
|
||||||
You are inside a building, a well house for a large spring.
|
|
||||||
#208
|
|
||||||
You are in a valley in the forest beside a stream tumbling along a
|
|
||||||
rocky bed.
|
|
||||||
#209
|
|
||||||
At your feet all the water of the stream splashes into a 2-inch slit
|
|
||||||
in the rock. Downstream the streambed is bare rock.
|
|
||||||
#210
|
|
||||||
You are in a 20-foot depression floored with bare dirt. Set into the
|
|
||||||
dirt is a strong steel grate mounted in concrete. A dry streambed
|
|
||||||
leads into the depression.
|
|
||||||
#211
|
|
||||||
You are in a small chamber beneath a 3x3 steel grate to the surface.
|
|
||||||
A low crawl over cobbles leads inward to the west.
|
|
||||||
#212
|
|
||||||
You are crawling over cobbles in a low passage. There is a dim light
|
|
||||||
at the east end of the passage.
|
|
||||||
#213
|
|
||||||
You are in a debris room filled with stuff washed in from the surface.
|
|
||||||
A low wide passage with cobbles becomes plugged with mud and debris
|
|
||||||
here, but an awkward canyon leads upward and west. A note on the wall
|
|
||||||
says "magic word XYZZY."
|
|
||||||
#214
|
|
||||||
You are in an awkward sloping east/west canyon.
|
|
||||||
#215
|
|
||||||
You are in a splendid chamber thirty feet high. The walls are frozen
|
|
||||||
rivers of orange stone. An awkward canyon and a good passage exit
|
|
||||||
from east and west sides of the chamber.
|
|
||||||
#216
|
|
||||||
At your feet is a small pit breathing traces of white mist. An east
|
|
||||||
passage ends here except for a small crack leading on.
|
|
||||||
|
|
||||||
Rough stone steps lead down the pit.
|
|
||||||
#217
|
|
||||||
You are at one end of a vast hall stretching forward out of sight to
|
|
||||||
the west. There are openings to either side. Nearby, a wide stone
|
|
||||||
staircase leads downward. The hall is filled with wisps of white mist
|
|
||||||
swaying to and fro almost as if alive. A cold wind blows up the
|
|
||||||
staircase. There is a passage at the top of a dome behind you.
|
|
||||||
|
|
||||||
Rough stone steps lead to the top of the dome.
|
|
||||||
#218
|
|
||||||
This is a low room with a crude note on the wall. The note says,
|
|
||||||
"you can't get it up the steps."
|
|
||||||
#219
|
|
||||||
You are on the east bank of a fissure slicing clear across the hall.
|
|
||||||
The mist is quite thick here, and the fissure is too wide to jump.
|
|
||||||
#220
|
|
||||||
You are on the west side of the fissure in the Hall of Mists.
|
|
||||||
#221
|
|
||||||
You are at the west end of Hall of Mists. A low wide crawl continues
|
|
||||||
west and another goes north. To the south is a little passage 6 feet
|
|
||||||
off the floor.
|
|
||||||
#222
|
|
||||||
You are in the Hall of the Mountain King, with passages off in all
|
|
||||||
directions.
|
|
||||||
#223
|
|
||||||
You are in the south side chamber.
|
|
||||||
#224
|
|
||||||
You are in the west side chamber of the Hall of the Mountain King.
|
|
||||||
A passage continues west and up here.
|
|
||||||
#225
|
|
||||||
You are in a low N/S passage at a hole in the floor. The hole goes
|
|
||||||
down to an E/W passage.
|
|
||||||
#226
|
|
||||||
You are in a large room, with a passage to the south, a passage to the
|
|
||||||
west, and a wall of broken rock to the east. There is a large "Y2" on
|
|
||||||
a rock in the room's center.
|
|
||||||
#227
|
|
||||||
You're at a low window overlooking a huge pit, which extends up out of
|
|
||||||
sight. A floor is indistinctly visible over 50 feet below. Traces of
|
|
||||||
white mist cover the floor of the pit, becoming thicker to the right.
|
|
||||||
Marks in the dust around the window would seem to indicate that
|
|
||||||
someone has been here recently. Directly across the pit from you and
|
|
||||||
25 feet away there is a similar window looking into a lighted room. A
|
|
||||||
shadowy figure can be seen there peering back at you.
|
|
||||||
|
|
||||||
The shadowy figure seems to be trying to attract your attention.
|
|
||||||
#228
|
|
||||||
The passage here is blocked by a recent cave-in.
|
|
||||||
#229
|
|
||||||
You are at the east end of a very long hall apparently without side
|
|
||||||
chambers. To the east a low wide crawl slants up. To the north a
|
|
||||||
round two foot hole slants down.
|
|
||||||
#230
|
|
||||||
You are at the west end of a very long featureless hall. The hall
|
|
||||||
joins up with a narrow north/south passage.
|
|
||||||
#231
|
|
||||||
You are at a crossover of a high N/S passage and a low E/W one.
|
|
||||||
#232
|
|
||||||
Dead end
|
|
||||||
#233
|
|
||||||
You are in a dirty broken passage. To the east is a crawl. To the
|
|
||||||
west is a large passage. Above you is a hole to another passage.
|
|
||||||
#234
|
|
||||||
You are on the brink of a small clean climbable pit. A crawl leads
|
|
||||||
west.
|
|
||||||
#235
|
|
||||||
You are in the bottom of a small pit with a little stream, which
|
|
||||||
enters and exits through tiny slits.
|
|
||||||
#236
|
|
||||||
You are in a large room full of dusty rocks. There is a big hole in
|
|
||||||
the floor. There are cracks everywhere, and a passage leading east.
|
|
||||||
#237
|
|
||||||
You are at a complex junction. A low hands and knees passage from the
|
|
||||||
north joins a higher crawl from the east to make a walking passage
|
|
||||||
going west. There is also a large room above. The air is damp here.
|
|
||||||
#238
|
|
||||||
You are in an anteroom leading to a large passage to the east. Small
|
|
||||||
passages go west and up. The remnants of recent digging are evident.
|
|
||||||
a sign in midair here says "Cave under construction beyond this point.
|
|
||||||
proceed at own risk. "[Witt Construction Company]"
|
|
||||||
#239
|
|
||||||
You are at Witt's end. Passages lead off in *all* directions.
|
|
||||||
#240
|
|
||||||
You're in a large room carved out of sedimentary rock. The floor and
|
|
||||||
walls are littered with bits of shells embedded in the stone. A
|
|
||||||
shallow passage proceeds downward, and a somewhat steeper one leads
|
|
||||||
up. A low hands and knees passage enters from the south.
|
|
||||||
#241
|
|
||||||
You are in an arched hall. A coral passage once continued up and east
|
|
||||||
from here, but is now blocked by debris. The air smells of sea water.
|
|
||||||
#242
|
|
||||||
You are in a long sloping corridor with ragged sharp walls.
|
|
||||||
#243
|
|
||||||
You are in a cul-de-sac about eight feet across. How's your french?
|
|
||||||
#244
|
|
||||||
You are in bedquilt, a long east/west passage with holes everywhere.
|
|
||||||
To explore at random, select north, south, up or down.
|
|
||||||
#245
|
|
||||||
You are in a room whose walls resemble swiss cheese. Obvious passages
|
|
||||||
go west, east, NE, and NW. Part of the room is occupied by a large
|
|
||||||
bedrock block.
|
|
||||||
#246
|
|
||||||
You are in the soft room. The walls are covered with heavy curtains,
|
|
||||||
the floor with a thick pile carpet. Moss covers the ceiling.
|
|
||||||
#247
|
|
||||||
You are at the east end of the Twopit room. The floor here is
|
|
||||||
littered with thin rock slabs, which make it easy to descend the pits.
|
|
||||||
There is a path here bypassing the pits to connect passages from east
|
|
||||||
and west. There are holes all over, but the only big one is on the
|
|
||||||
wall directly over the west pit where you can't get to it.
|
|
||||||
#248
|
|
||||||
You are at the west end of the Twopit room. There is a large hole in
|
|
||||||
the wall above the pit at this end of the room.
|
|
||||||
#249
|
|
||||||
You are at the bottom of the eastern pit in the Twopit room. There is
|
|
||||||
a small pool of oil in one corner of the pit.
|
|
||||||
#250
|
|
||||||
You are at the bottom of the western pit in the Twopit room. There is
|
|
||||||
a large hole in the wall about 25 feet above you.
|
|
||||||
#251
|
|
||||||
You are in a large low circular chamber whose floor is an immense slab
|
|
||||||
fallen from the ceiling (slab room). East and west there once were
|
|
||||||
large passages, but they are now filled with boulders. Low small
|
|
||||||
passages go north and south, and the south one quickly bends west
|
|
||||||
around the boulders.
|
|
||||||
#252
|
|
||||||
This is the oriental room. Ancient oriental cave drawings cover the
|
|
||||||
walls. A gently sloping passage leads upward to the north, another
|
|
||||||
passage leads SE, and a hands and knees crawl leads west.
|
|
||||||
#253
|
|
||||||
You are in a large low room. Crawls lead north, SE, and SW.
|
|
||||||
#254
|
|
||||||
You are in a long winding corridor sloping out of sight in both
|
|
||||||
directions.
|
|
||||||
#255
|
|
||||||
Dead end crawl.
|
|
||||||
#256
|
|
||||||
You are following a wide path around the outer edge of a large cavern.
|
|
||||||
Far below, through a heavy white mist, strange splashing noises can be
|
|
||||||
heard. The mist rises up through a fissure in the ceiling. The path
|
|
||||||
exits to the south and west.
|
|
||||||
#257
|
|
||||||
You are in an alcove. A small NW path seems to widen after a short
|
|
||||||
distance. An extremely tight tunnel leads east. It looks like a very
|
|
||||||
tight squeeze. An eerie light can be seen at the other end.
|
|
||||||
#258
|
|
||||||
You're in a small chamber lit by an eerie green light. An extremely
|
|
||||||
narrow tunnel exits to the west. A dark corridor leads NE.
|
|
||||||
#259
|
|
||||||
You're in the dark-room. A corridor leading south is the only exit.
|
|
||||||
A massive stone tablet embedded in the wall reads:
|
|
||||||
"Congratulations on bringing light into the dark-room!"
|
|
||||||
#260
|
|
||||||
You are on one side of a large, deep chasm. A heavy white mist rising
|
|
||||||
up from below obscures all view of the far side. A SW path leads away.
|
|
||||||
|
|
||||||
A rickety wooden bridge extends across the chasm, vanishing into the
|
|
||||||
mist. A sign posted on the bridge reads, "STOP! Pay Troll!"
|
|
||||||
#261
|
|
||||||
You are on the far side of the chasm. A NE path leads away from the
|
|
||||||
chasm on this side.
|
|
||||||
|
|
||||||
A rickety wooden bridge extends across the chasm, vanishing into the
|
|
||||||
gloom. A sign posted on the bridge reads: "Stop! Pay troll!"
|
|
||||||
#262
|
|
||||||
You're in a long east/west corridor. A faint rumbling noise can be
|
|
||||||
heard in the distance.
|
|
||||||
#263
|
|
||||||
The path forks here. The left fork leads northeast. A dull rumbling
|
|
||||||
seems to get louder in that direction. The right fork leads southeast
|
|
||||||
down a gentle slope. The main corridor enters from the west.
|
|
||||||
#264
|
|
||||||
You are walking along a gently sloping north/south passage lined with
|
|
||||||
oddly shaped limestone formations.
|
|
||||||
#265
|
|
||||||
The walls are quite warm here. From the north can be heard a steady
|
|
||||||
roar, so loud that the entire cave seems to be trembling. Another
|
|
||||||
passage leads south, and a low crawl goes east.
|
|
||||||
#266
|
|
||||||
You are in a small chamber filled with large boulders. The walls are
|
|
||||||
very warm, causing the air in the room to be almost stifling from the
|
|
||||||
heat. The only exit is a crawl heading west, through which is coming
|
|
||||||
a low rumbling.
|
|
||||||
#267
|
|
||||||
You are on the edge of a breath-taking view. Far below you is an
|
|
||||||
active volcano, from which great gouts of molten lava come surging
|
|
||||||
out, cascading back down into the depths. The glowing rock fills the
|
|
||||||
farthest reaches of the cavern with a blood-red glare, giving every-
|
|
||||||
thing an eerie, macabre appearance. The air is filled with flickering
|
|
||||||
sparks of ash and a heavy smell of brimstone. The walls are hot to
|
|
||||||
the touch, and the thundering of the volcano drowns out all other
|
|
||||||
sounds. Embedded in the jagged roof far overhead are myriad twisted
|
|
||||||
formations composed of pure white alabaster, which scatter the murky
|
|
||||||
light into sinister apparitions upon the walls. To one side is a deep
|
|
||||||
gorge, filled with a bizarre chaos of tortured rock which seems to
|
|
||||||
have been crafted by the devil himself. An immense river of fire
|
|
||||||
crashes out from the depths of the volcano, burns its way through the
|
|
||||||
gorge, and plummets into a bottomless pit far off to your left. To
|
|
||||||
the right, an immense geyser of blistering steam erupts continuously
|
|
||||||
from a barren island in the center of a sulfurous lake, which bubbles
|
|
||||||
ominously. The far right wall is aflame with an incandescence of its
|
|
||||||
own, which lends an additional infernal splendor to the already
|
|
||||||
hellish scene. A dark, foreboding passage exits to the south.
|
|
||||||
#268
|
|
||||||
You are standing at the entrance to a large, barren room. A sign
|
|
||||||
posted above the entrance reads: "Caution! Bear in room!"
|
|
||||||
#269
|
|
||||||
You are inside a barren room. The center of the room is completely
|
|
||||||
empty except for some dust. Marks in the dust lead away toward the
|
|
||||||
far end of the room. The only exit is the way you came in.
|
|
||||||
#270
|
|
||||||
You are in a long, narrow corridor stretching out of sight to the
|
|
||||||
west. At the eastern end is a hole through which you can see a
|
|
||||||
profusion of leaves.
|
|
||||||
#271
|
|
||||||
You are in the giant room. The ceiling here is too high up for your
|
|
||||||
lamp to show it. Cavernous passages lead east, north, and south. On
|
|
||||||
the west wall is scrawled the inscription, "FEE FIE FOE FOO" [sic].
|
|
||||||
#272
|
|
||||||
The passage here is blocked by a recent cavein.
|
|
||||||
#273
|
|
||||||
You are at one end of an immense north/south passage.
|
|
||||||
#274
|
|
||||||
You are in a magnificent cavern with a rushing stream, which cascades
|
|
||||||
over a sparkling waterfall into a roaring whirlpool which disappears
|
|
||||||
through a hole in the floor. Passages exit to the south and west.
|
|
||||||
#275
|
|
||||||
You are at the top of a steep incline above a large room. You could
|
|
||||||
climb down here, but you would not be able to climb up. There is a
|
|
||||||
passage leading back to the north.
|
|
||||||
#276
|
|
||||||
You are in a secret N/S canyon above a sizable passage.
|
|
||||||
#277
|
|
||||||
A large stalactite extends from the roof and almost reaches the floor
|
|
||||||
below. You could climb down it, and jump from it to the floor, but
|
|
||||||
having done so you would be unable to reach it to climb back up.
|
|
||||||
|
|
||||||
The maze continues at this level.
|
|
||||||
#278
|
|
||||||
You are in a secret canyon at a junction of three canyons, bearing
|
|
||||||
north, south, and SE. The north one is as tall as the other two
|
|
||||||
combined.
|
|
||||||
#279
|
|
||||||
You are in a secret N/S canyon above a large room.
|
|
||||||
#280
|
|
||||||
You are in a north/south canyon about 25 feet across. The floor is
|
|
||||||
covered by white mist seeping in from the north. The walls extend
|
|
||||||
upward for well over 100 feet. Suspended from some unseen point far
|
|
||||||
above you, an enormous two-sided mirror is hanging parallel to and
|
|
||||||
midway between the canyon walls. (The mirror is obviously provided
|
|
||||||
for the use of the dwarves, who as you know, are extremely vain.) A
|
|
||||||
small window can be seen in either wall, some fifty feet up.
|
|
||||||
#281
|
|
||||||
You are at the edge of a large underground reservoir. An opaque cloud
|
|
||||||
of white mist fills the room and rises rapidly upward. The lake is
|
|
||||||
fed by a stream, which tumbles out of a hole in the wall about 10 feet
|
|
||||||
overhead and splashes noisily into the water somewhere within the
|
|
||||||
mist. The only passage goes back toward the south.
|
|
||||||
#282
|
|
||||||
You are in a secret canyon which exits to the north and east.
|
|
||||||
#283
|
|
||||||
You're in the secret E/W canyon above a tight canyon.
|
|
||||||
#284
|
|
||||||
You are at a wide place in a very tight N/S canyon.
|
|
||||||
#285
|
|
||||||
The canyon here becomes too tight to go on.
|
|
||||||
#286
|
|
||||||
You are in a tall E/W canyon. A low tight crawl goes 3 feet north and
|
|
||||||
seems to open up.
|
|
||||||
#287
|
|
||||||
The canyon runs into a maze of boulders -- dead end.
|
|
||||||
#288
|
|
||||||
You are in a maze of twisty little passages, all alike.
|
|
||||||
#298
|
|
||||||
You are near a large pit beside a large stalactite in the maze.
|
|
||||||
The stalactite is about 30 feet long, allowing you to descend
|
|
||||||
it. However, due to the smoothness of the stalactite you will
|
|
||||||
probably be unable to climb back up again.
|
|
||||||
#299
|
|
||||||
The threatening little dwarf pulls out a sharp, nasty knife but
|
|
||||||
suddenly freezes.
|
|
||||||
|
|
||||||
The burly troll notices the little dwarf and appears to become very angry.
|
|
||||||
|
|
||||||
The little dwarf frantically looks from side to side, the burly troll
|
|
||||||
takes a sudden step towards the little dwarf.
|
|
||||||
|
|
||||||
The little dwarf makes an odd squeal, steps back and trips on an outcropping,
|
|
||||||
falling with a soft *thud* before scrambling out of sight in a cloud of dust.
|
|
||||||
#300
|
|
||||||
Dead end.
|
|
||||||
#301
|
|
||||||
Welcome to adventure.! Would you like instructions?
|
|
||||||
#302
|
|
||||||
Somewhere nearby is Colossal Cave, where others have found fortunes in
|
|
||||||
treasure and gold, though it is rumored that some who enter are never
|
|
||||||
seen again. Magic is said to work in the cave. I will be your eyes
|
|
||||||
and hands. Direct me with commands such as get, take, or look. Since you
|
|
||||||
need to move around, you must usually enter compass directions
|
|
||||||
(N,NE,E,SE,S,SW,W,NW or up or down), although you may sometimes use
|
|
||||||
more vague verbs with with to move. I know of several objects in this
|
|
||||||
game, such as a lamp and a bottle. I also know of special objects in the
|
|
||||||
cave. Some of these objects have side effects, ie there is a rod in the
|
|
||||||
cave that scares a little bird.
|
|
||||||
-----------------------------------------------------------------
|
|
||||||
The object of this game is to gather as many treasures as you can and
|
|
||||||
put them back in the house. You also run the risk of getting robbed or
|
|
||||||
killed by some rather unfriendly inhabitants of the cave.
|
|
||||||
----------------------------------------------------------------
|
|
||||||
There are some useful commands that you should know about:
|
|
||||||
--- Brief, Long, and Short - these commands control the amount of
|
|
||||||
--- detail you get in descriptions.
|
|
||||||
--- Look (or L) - gives a detailed description of your surroundings.
|
|
||||||
--- Inventory (or I) tells you what you are carrying.
|
|
||||||
--- Quit, Stop or End - these are self-explanatory.
|
|
||||||
--- Save - by typing this, you may save your game and continue it at
|
|
||||||
--- a later time.
|
|
||||||
--- Continue - lets you continue an old game.
|
|
||||||
--- Score - tells you hw well you're doing.
|
|
||||||
|
|
||||||
Other helpful functions include:
|
|
||||||
* multiple commands on one input line, ie:
|
|
||||||
"Go south, get car, keys, Start car." (example only)
|
|
||||||
--------------------------------------------------------------
|
|
||||||
"Adventure" is a version of the game created by Willy Crowther and
|
|
||||||
Dan Woods at M.I.T.
|
|
||||||
--------------------------------------------------------------
|
|
||||||
#303
|
|
||||||
I'm sorry, but the magazine is written in Dwarvish.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
1,0
|
|
||||||
2,1
|
|
||||||
3,235
|
|
||||||
4,307
|
|
||||||
5,365
|
|
||||||
6,400
|
|
||||||
7,531
|
|
||||||
8,601
|
|
||||||
9,673
|
|
||||||
10,715
|
|
||||||
11,742
|
|
||||||
12,771
|
|
||||||
13,864
|
|
||||||
14,914
|
|
||||||
15,960
|
|
||||||
16,987
|
|
||||||
17,1029
|
|
||||||
18,1219
|
|
||||||
19,1245
|
|
||||||
20,1350
|
|
||||||
21,1369
|
|
||||||
22,1397
|
|
||||||
23,1430
|
|
||||||
24,1488
|
|
||||||
25,1570
|
|
||||||
26,1713
|
|
||||||
27,1858
|
|
||||||
28,1928
|
|
||||||
29,2074
|
|
||||||
30,2137
|
|
||||||
31,2224
|
|
||||||
32,2288
|
|
||||||
33,2334
|
|
||||||
34,2564
|
|
||||||
35,2632
|
|
||||||
36,2657
|
|
||||||
37,2684
|
|
||||||
38,2797
|
|
||||||
39,2828
|
|
||||||
40,2874
|
|
||||||
41,2931
|
|
||||||
42,2966
|
|
||||||
43,3029
|
|
||||||
44,3098
|
|
||||||
45,3159
|
|
||||||
46,3236
|
|
||||||
47,3280
|
|
||||||
48,3357
|
|
||||||
49,3456
|
|
||||||
50,3531
|
|
||||||
51,3585
|
|
||||||
52,3699
|
|
||||||
53,3790
|
|
||||||
54,3861
|
|
||||||
55,3944
|
|
||||||
56,4045
|
|
||||||
57,4109
|
|
||||||
58,4171
|
|
||||||
59,4253
|
|
||||||
60,4347
|
|
||||||
61,6
|
|
||||||
62,4584
|
|
||||||
63,4672
|
|
||||||
64,4737
|
|
||||||
65,4815
|
|
||||||
66,4873
|
|
||||||
67,4930
|
|
||||||
68,4987
|
|
||||||
69,5022
|
|
||||||
70,5131
|
|
||||||
71,5186
|
|
||||||
72,5225
|
|
||||||
73,5285
|
|
||||||
74,5320
|
|
||||||
75,5360
|
|
||||||
76,5535
|
|
||||||
77,5744
|
|
||||||
78,5880
|
|
||||||
79,6048
|
|
||||||
80,6092
|
|
||||||
81,6213
|
|
||||||
200,6260
|
|
||||||
205,6315
|
|
||||||
206,6464
|
|
||||||
207,6626
|
|
||||||
208,6693
|
|
||||||
209,6779
|
|
||||||
210,6909
|
|
||||||
211,7082
|
|
||||||
212,7210
|
|
||||||
213,7320
|
|
||||||
214,7565
|
|
||||||
215,7620
|
|
||||||
216,7807
|
|
||||||
217,7979
|
|
||||||
218,8377
|
|
||||||
219,8484
|
|
||||||
220,8628
|
|
||||||
221,8697
|
|
||||||
222,8861
|
|
||||||
223,8948
|
|
||||||
224,8990
|
|
||||||
225,9103
|
|
||||||
226,9203
|
|
||||||
227,9383
|
|
||||||
228,9935
|
|
||||||
229,9991
|
|
||||||
230,10168
|
|
||||||
231,10287
|
|
||||||
232,10358
|
|
||||||
233,10374
|
|
||||||
234,10516
|
|
||||||
235,10598
|
|
||||||
236,10708
|
|
||||||
237,10854
|
|
||||||
238,11071
|
|
||||||
239,11344
|
|
||||||
240,11414
|
|
||||||
241,11685
|
|
||||||
242,11834
|
|
||||||
243,11901
|
|
||||||
244,11976
|
|
||||||
245,12108
|
|
||||||
246,12271
|
|
||||||
247,12411
|
|
||||||
248,12753
|
|
||||||
249,12879
|
|
||||||
250,13004
|
|
||||||
251,13133
|
|
||||||
252,13436
|
|
||||||
253,13640
|
|
||||||
254,13708
|
|
||||||
255,13792
|
|
||||||
256,13815
|
|
||||||
257,14066
|
|
||||||
258,14275
|
|
||||||
259,14412
|
|
||||||
260,14597
|
|
||||||
261,14882
|
|
||||||
262,15113
|
|
||||||
263,15212
|
|
||||||
264,15424
|
|
||||||
265,15537
|
|
||||||
266,15730
|
|
||||||
267,15966
|
|
||||||
268,17284
|
|
||||||
269,17418
|
|
||||||
270,17623
|
|
||||||
271,17783
|
|
||||||
272,17999
|
|
||||||
273,18054
|
|
||||||
274,18115
|
|
||||||
275,18330
|
|
||||||
276,18511
|
|
||||||
277,18574
|
|
||||||
278,18823
|
|
||||||
279,18974
|
|
||||||
280,19032
|
|
||||||
281,19514
|
|
||||||
282,19853
|
|
||||||
283,19922
|
|
||||||
284,19983
|
|
||||||
285,20042
|
|
||||||
286,20093
|
|
||||||
287,20190
|
|
||||||
288,20250
|
|
||||||
298,20313
|
|
||||||
299,20554
|
|
||||||
300,21003
|
|
||||||
301,21020
|
|
||||||
302,21080
|
|
||||||
303,22968
|
|
||||||
-999,-999
|
|
||||||
30
|
|
||||||
54
|
|
||||||
86
|
|
||||||
140
|
|
||||||
189
|
|
||||||
4410
|
|
||||||
4438
|
|
||||||
4456
|
|
||||||
4512
|
|
||||||
4536
|
|
||||||
-999
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
3,0,6,0,4,0,2,0,0,0
|
|
||||||
1,0,8,0,2,0,4,0,0,0
|
|
||||||
2,0,1,0,4,0,7,0,0,0
|
|
||||||
1,0,3,0,5,0,2,0,0,0
|
|
||||||
2,0,6,0,4,0,1,0,0,0
|
|
||||||
2,0,7,0,8,0,5,0,0,0
|
|
||||||
0,0,0,0,0,0,6,0,0,0
|
|
||||||
6,0,3,0,9,0,4,0,0,0
|
|
||||||
8,0,3,0,10,0,4,0,0,0
|
|
||||||
9,0,0,0,11,0,0,0,0,11
|
|
||||||
0,0,10,0,0,0,12,0,10,0
|
|
||||||
0,0,11,0,0,0,13,0,0,0
|
|
||||||
0,0,12,0,0,0,14,0,14,0
|
|
||||||
0,0,13,0,0,0,15,0,15,13
|
|
||||||
0,0,14,0,0,0,16,0,0,0
|
|
||||||
0,0,15,0,0,0,0,0,0,17
|
|
||||||
22,0,0,0,18,0,19,0,16,22
|
|
||||||
17,0,0,0,0,0,0,0,0,0
|
|
||||||
0,0,17,0,0,0,20,0,0,0
|
|
||||||
0,0,19,0,0,0,21,0,0,0
|
|
||||||
20,0,20,0,88,0,29,0,0,0
|
|
||||||
25,0,17,0,23,83,24,0,17,0
|
|
||||||
22,0,0,0,0,0,0,0,0,0
|
|
||||||
0,0,22,0,0,0,31,0,31,0
|
|
||||||
26,0,0,0,22,0,0,0,0,33
|
|
||||||
0,0,28,0,25,0,27,0,0,0
|
|
||||||
0,0,26,0,0,0,0,0,0,0
|
|
||||||
0,0,0,0,0,26,0,0,0,0
|
|
||||||
31,0,21,0,0,0,30,0,21,31
|
|
||||||
31,0,29,0,94,0,0,0,0,0
|
|
||||||
32,0,24,0,30,0,29,0,0,0
|
|
||||||
31,0,0,0,0,0,0,0,0,0
|
|
||||||
0,0,34,0,0,0,36,0,25,0
|
|
||||||
0,0,0,0,0,0,33,0,0,35
|
|
||||||
0,0,0,0,0,0,0,0,34,0
|
|
||||||
0,0,33,0,0,0,0,0,25,37
|
|
||||||
40,0,38,0,0,0,44,0,36,0
|
|
||||||
0,0,39,0,0,0,37,0,37,0
|
|
||||||
255,255,255,255,255,255,255,255,255,255
|
|
||||||
0,0,0,0,37,0,0,0,41,42
|
|
||||||
0,0,0,0,0,0,0,0,0,43
|
|
||||||
0,0,0,0,0,0,0,0,40,43
|
|
||||||
0,0,0,0,0,0,0,0,42,0
|
|
||||||
255,0,37,0,255,0,45,0,255,255
|
|
||||||
0,44,46,0,0,0,47,52,0,0
|
|
||||||
0,0,0,0,0,0,45,0,0,0
|
|
||||||
0,0,45,0,0,0,48,0,0,49
|
|
||||||
0,0,47,0,0,0,51,0,0,50
|
|
||||||
0,0,0,0,0,0,0,0,47,0
|
|
||||||
0,0,0,0,0,0,0,0,48,0
|
|
||||||
44,0,0,0,48,0,0,0,79,0
|
|
||||||
56,0,0,45,0,0,53,0,0,0
|
|
||||||
55,0,0,52,0,54,0,0,0,0
|
|
||||||
0,0,0,0,0,0,0,0,60,53
|
|
||||||
0,0,0,0,53,0,0,0,0,0
|
|
||||||
0,0,0,0,52,0,57,0,0,0
|
|
||||||
0,0,58,0,0,0,0,56,0,0
|
|
||||||
0,59,0,0,0,0,57,0,0,0
|
|
||||||
0,0,0,0,58,0,0,0,0,0
|
|
||||||
0,61,0,0,0,54,0,0,0,54
|
|
||||||
0,62,0,0,0,60,0,0,0,0
|
|
||||||
0,0,63,0,0,0,61,0,0,0
|
|
||||||
0,65,0,64,0,0,62,0,0,0
|
|
||||||
63,0,0,0,68,0,0,0,0,0
|
|
||||||
67,0,66,0,63,0,0,0,0,0
|
|
||||||
0,0,0,0,0,0,65,0,0,0
|
|
||||||
0,0,0,0,65,0,0,0,0,0
|
|
||||||
0,0,69,0,0,0,64,0,0,0
|
|
||||||
0,0,0,0,0,0,68,0,0,0
|
|
||||||
0,0,50,0,0,0,71,0,0,50
|
|
||||||
73,0,70,0,72,0,0,0,0,0
|
|
||||||
0,71,0,0,0,0,0,0,0,0
|
|
||||||
74,0,0,0,71,0,0,0,0,0
|
|
||||||
0,0,0,0,73,0,75,0,0,0
|
|
||||||
74,0,0,0,0,0,0,0,0,53
|
|
||||||
78,0,0,0,77,0,0,0,0,45
|
|
||||||
76,0,0,0,0,0,0,0,0,93
|
|
||||||
27,0,0,44,76,0,0,0,0,0
|
|
||||||
80,0,0,0,82,0,0,0,0,51
|
|
||||||
81,0,0,0,79,0,0,0,0,0
|
|
||||||
0,0,0,0,80,0,0,0,0,0
|
|
||||||
79,0,83,0,0,0,0,0,0,0
|
|
||||||
0,0,22,0,0,0,82,0,0,84
|
|
||||||
86,0,0,0,85,0,0,0,0,0
|
|
||||||
84,0,0,0,0,0,0,0,0,0
|
|
||||||
45,0,84,0,0,0,87,0,0,0
|
|
||||||
0,0,0,86,0,0,0,0,0,0
|
|
||||||
89,82,91,95,90,83,92,91,95,94
|
|
||||||
95,96,91,90,89,88,91,95,93,97
|
|
||||||
92,92,91,93,88,97,88,96,99,87
|
|
||||||
91,89,94,90,93,95,89,92,0,0
|
|
||||||
95,97,93,96,94,95,21,92,0,0
|
|
||||||
90,96,92,94,88,30,92,90,0,0
|
|
||||||
98,89,90,91,89,93,95,97,0,0
|
|
||||||
93,94,96,92,97,95,94,92,0,0
|
|
||||||
92,99,97,96,89,94,90,90,91,92
|
|
||||||
98,89,92,91,90,93,94,95,96,98
|
|
||||||
95,90,93,91,94,92,90,99,98,15
|
|
||||||
88,89,93,97,100,89,96,95,0,0
|
|
||||||
0,0,0,0,99,0,0,0,0,0
|
|
||||||
|
|
@ -1,585 +0,0 @@
|
||||||
10 REM Pneuma - A space adventure
|
|
||||||
20 REM ========== backstory and instructions ==========
|
|
||||||
30 PRINT "********************************" : PRINT
|
|
||||||
35 PRINT " Pneuma - A space adventure" : PRINT
|
|
||||||
40 PRINT "********************************": PRINT
|
|
||||||
45 PRINT "To get instructions, type 'help'"
|
|
||||||
50 PRINT
|
|
||||||
60 PRINT "You wake up in your bunk, in the sleeping quarters of the starship Pneuma. You can't"
|
|
||||||
65 PRINT "remember much. You went to bed feeling sick and after a feverish few hours tossing and"
|
|
||||||
70 PRINT "turning, feeling like you were burning up, you eventually fell asleep." : PRINT
|
|
||||||
75 PRINT "Now, your sheets and night clothes are damp with sweat, and you have a raging thirst."
|
|
||||||
80 PRINT "You have a sore throat and the mother of all headaches, like your brain has been boiling"
|
|
||||||
85 PRINT "in your skull. In fact, you're no longer sure exactly where you are ... you seem to be"
|
|
||||||
90 PRINT "suffering from some sort of amnesia ...": PRINT
|
|
||||||
95 REM set up environment
|
|
||||||
100 GOSUB 2700
|
|
||||||
500 REM setup room descriptions
|
|
||||||
510 GOSUB 3000
|
|
||||||
520 REM setup up interative descriptions
|
|
||||||
530 GOSUB 5000
|
|
||||||
540 REM setup dialogue
|
|
||||||
550 GOSUB 7000
|
|
||||||
700 REM ========== main loop ==========
|
|
||||||
701 IF WPL <> 99 THEN GOSUB 8400 : REM wraith-hound movement
|
|
||||||
702 REM show room details
|
|
||||||
703 PRINT "You are in the " ; LO$ ( PL ) : PRINT
|
|
||||||
705 GOSUB 4010 : REM print room description
|
|
||||||
706 GOSUB 8000 : REM tracker info if carried
|
|
||||||
707 IF WPL <> 99 THEN GOSUB 8200 : REM wraith-hound proximity check
|
|
||||||
709 IF WPL = PL THEN GOSUB 11000 : REM fight wraith-hound
|
|
||||||
710 INPUT "What now? " ; I$
|
|
||||||
715 PRINT
|
|
||||||
716 MOVE = 1
|
|
||||||
720 IF LEFT$ ( LOWER$ ( I$ ) , 4 ) = "get " THEN MOVE = 0 : GOSUB 1400
|
|
||||||
730 IF LEFT$ ( LOWER$ ( I$ ) , 5 ) = "take " THEN MOVE = 0 : GOSUB 1700
|
|
||||||
740 IF LEFT$ ( LOWER$ ( I$ ) , 5 ) = "drop " THEN MOVE = 0 : GOSUB 2000
|
|
||||||
750 IF LEFT$ ( LOWER$ ( I$ ) , 8 ) = "examine " THEN MOVE = 0 : GOSUB 2300
|
|
||||||
760 IF LEFT$ ( LOWER$ ( I$ ) , 4 ) = "look" THEN MOVE = 0 : GOSUB 4010
|
|
||||||
765 IF LEFT$ ( LOWER$ ( I$ ) , 4 ) = "help" THEN MOVE = 0 : GOSUB 4130
|
|
||||||
767 IF LEFT$ ( LOWER$ ( I$ ) , 4 ) = "use " THEN MOVE = 0 : GOSUB 9000
|
|
||||||
770 IF LOWER$ ( I$ ) = "i" OR LOWER$ ( I$ ) = "inventory" THEN MOVE = 0 : GOSUB 1000
|
|
||||||
775 IF LEFT$ ( LOWER$ ( I$ ) , 8 ) = "talk to " THEN MOVE = 0 : GOSUB 2630
|
|
||||||
780 IF LEFT$ ( LOWER$ ( I$ ) , 1 ) = "q" THEN GOSUB 2600
|
|
||||||
785 IF LEFT$ ( LOWER$ ( I$ ) , 3 ) = "go " THEN GOSUB 1100
|
|
||||||
790 IF LOWER$ ( I$ ) = "f" OR LOWER$ ( I$ ) = "forward" THEN GOSUB 1200
|
|
||||||
800 IF LOWER$ ( I$ ) = "a" OR LOWER$ ( I$ ) = "aft" THEN GOSUB 1200
|
|
||||||
810 IF LOWER$ ( I$ ) = "p" OR LOWER$ ( I$ ) = "port" THEN GOSUB 1200
|
|
||||||
820 IF LOWER$ ( I$ ) = "s" OR LOWER$ ( I$ ) = "starboard" THEN GOSUB 1200
|
|
||||||
830 IF LOWER$ ( I$ ) = "u" OR LOWER$ ( I$ ) = "up" THEN GOSUB 1200
|
|
||||||
840 IF LOWER$ ( I$ ) = "d" OR LOWER$ ( I$ ) = "down" THEN GOSUB 1200
|
|
||||||
895 IF MOVE = 1 THEN GOTO 700 ELSE GOTO 710
|
|
||||||
900 STOP
|
|
||||||
995 REM ========== actions ==========
|
|
||||||
1000 REM list the player's inventory
|
|
||||||
1005 PRINT "You have the following items:" : PRINT
|
|
||||||
1010 FOR I = 0 TO OC - 1
|
|
||||||
1020 IF OL ( I ) = 0 THEN PRINT OB$ ( I )
|
|
||||||
1030 NEXT I
|
|
||||||
1035 PRINT
|
|
||||||
1040 RETURN
|
|
||||||
1100 REM fully written out move (e.g. 'go aft')
|
|
||||||
1110 D$ = MID$ ( LOWER$(I$) , 4 , 1 )
|
|
||||||
1120 GOSUB 1300
|
|
||||||
1130 RETURN
|
|
||||||
1200 REM abbreviated move (e.g. 'a' or 'aft')
|
|
||||||
1210 D$ = LOWER$( I$ )
|
|
||||||
1220 GOSUB 1300
|
|
||||||
1230 RETURN
|
|
||||||
1300 REM go to the player's new location (PL)
|
|
||||||
1310 IF D$ = "f" THEN NPL = VAL ( MID$ ( EX$ ( PL ) , 1 , 2 ) )
|
|
||||||
1320 IF D$ = "a" THEN NPL = VAL ( MID$ ( EX$ ( PL ) , 3 , 2 ) )
|
|
||||||
1330 IF D$ = "p" THEN NPL = VAL ( MID$ ( EX$ ( PL ) , 5 , 2 ) )
|
|
||||||
1340 IF D$ = "s" THEN NPL = VAL ( MID$ ( EX$ ( PL ) , 7 , 2 ) )
|
|
||||||
1345 IF D$ = "u" THEN NPL = VAL ( MID$ ( EX$ ( PL ) , 9 , 2 ) )
|
|
||||||
1350 IF D$ = "d" THEN NPL = VAL ( MID$ ( EX$ ( PL ) , 11 , 2 ) )
|
|
||||||
1355 IF NPL = 0 THEN PRINT "You can't go that way." : PRINT ELSE PL = NPL
|
|
||||||
1360 RETURN
|
|
||||||
1400 REM get command
|
|
||||||
1405 F=-1: R$=""
|
|
||||||
1410 R$ = MID$(LOWER$(I$), 5) : REM R$ is the requested object
|
|
||||||
1420 REM get the object ID
|
|
||||||
1430 FOR I= 0 TO OC-1
|
|
||||||
1440 IF OB$(I) = R$ THEN F=I : REM object exists
|
|
||||||
1450 NEXT I
|
|
||||||
1460 REM can't find the item?
|
|
||||||
1470 IF F=-1 THEN PRINT "You can't take that." : PRINT : RETURN
|
|
||||||
1480 IF OL(F) <> PL THEN PRINT "That item doesn't appear to be around here." : PRINT : RETURN
|
|
||||||
1490 IF OL(F)=0 THEN PRINT "You already have that item." : PRINT: RETURN
|
|
||||||
1520 OL(F)=0 : REM add the item to the inventory
|
|
||||||
1530 PRINT "You've picked up ";OB$(F); "." : PRINT
|
|
||||||
1540 RETURN
|
|
||||||
1700 REM take command
|
|
||||||
1710 F=-1: R$=""
|
|
||||||
1720 R$ = MID$(LOWER$(I$), 6) : REM R$ is the requested object
|
|
||||||
1730 GOTO 1420 : REM use the same logic as the get command
|
|
||||||
2000 REM drop command
|
|
||||||
2010 F=-1: R$=""
|
|
||||||
2020 R$ = MID$(LOWER$(I$), 6) : REM R$ is the requested object
|
|
||||||
2030 FOR I= 0 TO OC-1
|
|
||||||
2040 IF OB$(I) = R$ THEN F=I : REM object exists
|
|
||||||
2050 NEXT I
|
|
||||||
2060 REM can't find it?
|
|
||||||
2070 IF F=-1 THEN PRINT "You don't have that." : PRINT: RETURN
|
|
||||||
2080 IF OL(F) <> 0 THEN PRINT "You aren't carrying that." : PRINT: RETURN
|
|
||||||
2090 OL(F) = PL : PRINT "You've dropped ";OB$(F); ".": PRINT: REM add the item to the current room
|
|
||||||
2095 IF F = SUIT THEN SUIT_WORN = 0
|
|
||||||
2110 RETURN
|
|
||||||
2300 REM examine command
|
|
||||||
2310 F=-1 : R$=""
|
|
||||||
2320 R$ = MID$(LOWER$(I$), 9) : REM R$ is the object to examine
|
|
||||||
2330 FOR I = 0 TO IC-1
|
|
||||||
2340 IF IO$(I) = R$ THEN F=I : REM object exists
|
|
||||||
2350 NEXT I
|
|
||||||
2360 REM can't find it?
|
|
||||||
2370 IF F=-1 THEN PRINT "You can't examine that." : PRINT : RETURN
|
|
||||||
2380 IF IL(F) <> PL THEN PRINT "There isn't one of these here." : PRINT : RETURN
|
|
||||||
2390 GOSUB 6000 : REM print result of examination
|
|
||||||
2400 RETURN
|
|
||||||
2600 REM quit command
|
|
||||||
2610 PRINT "Farewell spacefarer ..."
|
|
||||||
2620 STOP
|
|
||||||
2630 REM talk to command
|
|
||||||
2635 F=-1 : R$ = ""
|
|
||||||
2640 R$ = MID$(LOWER$(I$), 9) : REM R$ is the person to talk to
|
|
||||||
2645 FOR I = 0 TO PC-1
|
|
||||||
2650 IF P$(I) = R$ THEN F=I : REM person exists
|
|
||||||
2655 NEXT I
|
|
||||||
2660 REM can't find them?
|
|
||||||
2665 IF F=-1 THEN PRINT "You've not met them." : PRINT : RETURN
|
|
||||||
2670 IF PLOC(F) <> PL THEN PRINT "They aren't here." : PRINT : RETURN
|
|
||||||
2675 GOSUB 7500 : REM print dialogue
|
|
||||||
2695 RETURN
|
|
||||||
2700 REM ========== set up environment ===========
|
|
||||||
2705 RC = 18 : REM room count
|
|
||||||
2710 DIM LO$ ( RC )
|
|
||||||
2715 INV = 0 : LO$ ( INV ) = "Inventory"
|
|
||||||
2720 GAL = 1 : LO$ ( GAL ) = "Galley"
|
|
||||||
2725 REC = 2 : LO$ ( REC ) = "Recreation/Dining Room"
|
|
||||||
2730 ARM = 3 : LO$ ( ARM ) = "Armoury"
|
|
||||||
2735 BDG = 4 : LO$ ( BDG ) = "Bridge"
|
|
||||||
2740 SLP = 5 : LO$ ( SLP ) = "Sleeping Quarters"
|
|
||||||
2745 MED = 6 : LO$ ( MED ) = "Medical Centre"
|
|
||||||
2750 GYM = 7 : LO$ ( GYM ) = "Gymnasium"
|
|
||||||
2755 LAC = 8 : LO$ ( LAC ) = "Lower Aft Corridor"
|
|
||||||
2760 ENG = 9 : LO$ ( ENG ) = "Engine Room"
|
|
||||||
2765 STO = 10 : LO$ ( STO ) = "Storeroom"
|
|
||||||
2770 MEN = 11 : LO$ ( MEN ) = "Menagerie"
|
|
||||||
2775 LAB = 12 : LO$ ( LAB ) = "Laboratory"
|
|
||||||
2780 LFC = 13 : LO$ ( LFC ) = "Lower Forward Corridor"
|
|
||||||
2785 POD = 14 : LO$ ( POD ) = "Pod Bay"
|
|
||||||
2790 AMC = 15 : LO$ ( AMC ) = "Aft Main Corridor"
|
|
||||||
2795 MMC = 16 : LO$ ( MMC ) = "Mid Main Corridor"
|
|
||||||
2800 FMC = 17 : LO$ ( FMC ) = "Forward Main Corridor"
|
|
||||||
2805 REM encoded room exits, two digits per direction f, a, p, s, u, d
|
|
||||||
2810 DIM EX$ ( RC )
|
|
||||||
2815 EX$ ( GAL ) = "020000150008"
|
|
||||||
2820 EX$ ( REC ) = "000100160000"
|
|
||||||
2825 EX$ ( ARM ) = "000000170000"
|
|
||||||
2830 EX$ ( BDG ) = "001700000000"
|
|
||||||
2835 EX$ ( SLP ) = "000015000000"
|
|
||||||
2840 EX$ ( MED ) = "070016000000"
|
|
||||||
2845 EX$ ( GYM ) = "000617000013"
|
|
||||||
2850 EX$ ( LAC ) = "100000090100"
|
|
||||||
2855 EX$ ( ENG ) = "000008000000"
|
|
||||||
2860 EX$ ( STO ) = "120800110000"
|
|
||||||
2865 EX$ ( MEN ) = "000010000000"
|
|
||||||
2870 EX$ ( LAB ) = "001000130000"
|
|
||||||
2875 EX$ ( LFC ) = "140012000700"
|
|
||||||
2880 EX$ ( POD ) = "001300000000"
|
|
||||||
2890 EX$ ( AMC ) = "160001050000"
|
|
||||||
2895 EX$ ( MMC ) = "171502060000"
|
|
||||||
2900 EX$ ( FMC ) = "041603070000"
|
|
||||||
2905 OC = 5 : REM object count
|
|
||||||
2910 DIM OB$ ( OC )
|
|
||||||
2915 PULSE = 0 : OB$ ( PULSE ) = "pulse rifle"
|
|
||||||
2920 SUIT = 1 : OB$ ( SUIT ) = "space suit"
|
|
||||||
2922 KNIFE = 2 : OB$ ( KNIFE ) = "knife"
|
|
||||||
2924 TRACKER = 3 : OB$ ( TRACKER ) = "tracker"
|
|
||||||
2926 SYRINGE = 4 : OB$ ( SYRINGE ) = "syringe"
|
|
||||||
2930 REM object locations
|
|
||||||
2932 REM location 0 = player's inventory
|
|
||||||
2934 DIM OL ( OC )
|
|
||||||
2936 OL ( PULSE ) = ARM
|
|
||||||
2937 OL ( SUIT ) = POD
|
|
||||||
2939 OL ( KNIFE ) = GAL
|
|
||||||
2940 OL ( TRACKER ) = GYM
|
|
||||||
2941 OL ( SYRINGE ) = MED
|
|
||||||
2942 IC = 5 : REM interactive object count
|
|
||||||
2944 DIM IO$ (IC)
|
|
||||||
2946 MEDLOG = 0 : IO$ ( MEDLOG ) = "medical log"
|
|
||||||
2948 PORTHOLE = 1 : IO$ (PORTHOLE) = "porthole"
|
|
||||||
2950 CONSOLE = 2 : IO$(CONSOLE) = "console"
|
|
||||||
2952 ENGINE = 3 : IO$(ENGINE)= "engine control"
|
|
||||||
2954 TERMINAL = 4 : IO$(TERMINAL) = "library terminal"
|
|
||||||
2960 REM interative object locations
|
|
||||||
2962 DIM IL ( IC )
|
|
||||||
2964 IL ( MEDLOG) = MED
|
|
||||||
2966 IL (PORTHOLE) = POD
|
|
||||||
2968 IL (CONSOLE) = BDG
|
|
||||||
2970 IL (ENGINE) = ENG
|
|
||||||
2971 IL (TERMINAL) = REC
|
|
||||||
2972 PC = 3 : REM person count
|
|
||||||
2974 DIM P$ ( PC )
|
|
||||||
2976 CHEF = 0 : P$ ( CHEF ) = "chef"
|
|
||||||
2978 RUNNER = 1 : P$ ( RUNNER ) = "runner"
|
|
||||||
2980 PILOT = 2 : P$ ( PILOT ) = "pilot"
|
|
||||||
2981 REM person locations
|
|
||||||
2983 DIM PLOC ( PC )
|
|
||||||
2985 PLOC ( CHEF ) = GAL
|
|
||||||
2987 PLOC ( RUNNER ) = GYM
|
|
||||||
2989 PLOC ( PILOT ) = BDG
|
|
||||||
2990 PL = SLP : REM initial player location
|
|
||||||
2992 WPL = MEN : REM wraith-hound initial location
|
|
||||||
2994 SUIT_WORN = 0 : REM is space suit worn?
|
|
||||||
2995 SHUTDOWN = 0 : REM are engines shut down?
|
|
||||||
2999 RETURN
|
|
||||||
3000 REM ========== room descriptions ==========
|
|
||||||
3010 DIM RD$ ( RC, 5 )
|
|
||||||
3015 REM inventory
|
|
||||||
3020 DATA "", "", "", "", ""
|
|
||||||
3025 REM galley
|
|
||||||
3030 DATA "The galley contains gleaming, stainless steel cupboards along the aft wall. A food"
|
|
||||||
3040 DATA "preparation surface is on the port wall, currently covered in rotting food. A chef"
|
|
||||||
3050 DATA "stands at the work surface, methodically chopping food even though everything has"
|
|
||||||
3060 DATA "already been thoroughly diced. There are doors in the starboard and forward walls and"
|
|
||||||
3070 DATA "a stairway leads downwards in the far corner."
|
|
||||||
3075 REM recreation room
|
|
||||||
3080 DATA "Space is clearly at a premium in this ship. The room doubles as both a dining and"
|
|
||||||
3090 DATA "recreation area. Long tables for dining are located on the port side, while couches"
|
|
||||||
3100 DATA "and low tables are scattered around the remaining space. A library terminal is switched"
|
|
||||||
3105 DATA "on in the corner. There are doors in the aft and starboard walls.", ""
|
|
||||||
3120 REM armoury
|
|
||||||
3130 DATA "Locked cabinets line the starboard wall. Each cabinet has a prominently displayed"
|
|
||||||
3140 DATA "notice on its door reading 'Weapons to be removed only when authorised by the Chief"
|
|
||||||
3150 DATA "Security Officer'. However, the door to one cupboard has been prized open, it is"
|
|
||||||
3160 DATA "warped and bent. This cupboard appears to be empty. The only exit is a starboard door.", ""
|
|
||||||
3170 REM bridge
|
|
||||||
3180 DATA "The bridge is the heart of the ship. A vast array of glowing screens and switches fill"
|
|
||||||
3190 DATA "every surface. On the screens are complex graphics providing detailed information about"
|
|
||||||
3200 DATA "the status of every system on the ship. Many of them are showing red warning symbols."
|
|
||||||
3210 DATA "There is a console directly in front of you, a pilot gripping the throttle."
|
|
||||||
3220 DATA "An aft exit leads back into the main corridor."
|
|
||||||
3225 REM sleeping quarters
|
|
||||||
3230 DATA "The sleeping quarters is filled with bunks, one up, one down. Several of the bunks"
|
|
||||||
3240 DATA "contain sleeping forms, some gently shoring. The room has a partition to separate"
|
|
||||||
3250 DATA "male and female bunks. Against the forward wall are two corresponding sets of heads."
|
|
||||||
3260 DATA "The room is messy, with discarded personal items everywhere ... on bunks, on the floor."
|
|
||||||
3270 DATA "There is a door in the port wall."
|
|
||||||
3275 REM medical centre
|
|
||||||
3280 DATA "The medical centre looks relatively normal, but there is evidence of discarded items"
|
|
||||||
3290 DATA "lying around the room. Blood filled syringes are scattered on a workbench, as well as"
|
|
||||||
3300 DATA "some bloodied bandanges. The words 'I'm losing myself' are scrawled messily in blood on"
|
|
||||||
3310 DATA "one wall. In the corner you can see a terminal. On the terminal screen is a portion"
|
|
||||||
3320 DATA "of the medical log. Exits lead port and forward."
|
|
||||||
3325 REM gymnasium
|
|
||||||
3330 DATA "The gymnasium is full of exercise equipment. A female runner is sprinting furiously on a"
|
|
||||||
3340 DATA "treadmill. She looks exhausted and emaciated, but she keeps running at top speed, almost at"
|
|
||||||
3350 DATA "a sprint. Her eyes remain fixed on the treadmill console. There are aft and port exits,"
|
|
||||||
3360 DATA "as well as a stairwell leading to the lower deck in the far corner.", ""
|
|
||||||
3370 REM lower aft corridor
|
|
||||||
3380 DATA "This is a featureless, utilitarian corridor. A stairwell leads upwards. There are also"
|
|
||||||
3390 DATA "exits leading starboard and forward.", "", "", ""
|
|
||||||
3400 REM engine room
|
|
||||||
3430 DATA "The engine room is characterised by a continual rumble, as though incredible energies are"
|
|
||||||
3440 DATA "barely being contained. There is an engine control in the far corner, festooned with"
|
|
||||||
3450 DATA "switches and engine readouts. A single exit leads out into the corridor.", "", ""
|
|
||||||
3460 REM storeroom
|
|
||||||
3480 DATA "The storeroom is full of crates, most neatly stacked, but with some scattered across the"
|
|
||||||
3490 DATA "floor, their contents spilling out. Along the port wall is a door marked 'Test specimens'."
|
|
||||||
3500 DATA "From behind the door, strange animal noises are audible ... snuffling sounds and the"
|
|
||||||
3510 DATA "occasional primate shriek. A dead man wearing a scuffed and torn lab coat is lying face down"
|
|
||||||
3520 DATA "in front of the specimen door. Two other exits lead forward and aft."
|
|
||||||
3525 REM menagerie
|
|
||||||
3530 DATA "The room is a hellhole. Cages stand open, while various animals roam about: chimpanzees,"
|
|
||||||
3540 DATA "dogs, and rats. Some of the rats are dead, having been savaged and eviscerated. The floor"
|
|
||||||
3550 DATA "and walls are smeared with animal faeces, and the smell is almost overpowering. A capsule,"
|
|
||||||
3552 DATA "its door ajar, is marked 'BIOWEAPON CONTAINMENT'. The capsule is empty."
|
|
||||||
3555 DATA "A single door to port leads back into the storeroom."
|
|
||||||
3560 REM laboratory
|
|
||||||
3570 DATA "The laboratory is full of scientific equipment, chemical glassware, electronic analysers,"
|
|
||||||
3580 DATA "fume cupboards, and two couches. The place looks disorded, like the rest of the ship, the"
|
|
||||||
3590 DATA "result of frenetic activity. A number of experiments seem to be in progress, with logbooks"
|
|
||||||
3600 DATA "and tablets covered in dense calculations and notes. Whatever has been happening in here,"
|
|
||||||
3610 DATA "it has been done with extreme urgency. Exits lead aft and to starboard."
|
|
||||||
3615 REM lower forward corridor
|
|
||||||
3620 DATA "This is a featureless, utilitarian corridor. A stairwell leads upwards. There are also"
|
|
||||||
3630 DATA "doors leading to port and forward.", "", "", ""
|
|
||||||
3660 REM pod bay
|
|
||||||
3670 DATA "You are in a large room, with a row of spacesuits hanging on the port wall. At the forward"
|
|
||||||
3680 DATA "end of the room is a small, two seater vehicle, capable of operating in space outside the"
|
|
||||||
3690 DATA "main ship for limited periods. In front of the small ship is the pod bay door, leading out"
|
|
||||||
3700 DATA "into space. There is a porthole on the far wall. There is a single exit leading aft.", ""
|
|
||||||
3710 REM aft main corridor
|
|
||||||
3720 DATA "The main corridor stretches away from you towards the front of the ship. It is featureless"
|
|
||||||
3730 DATA "and utilitarian. The lighting is dim. You can see doors either side of you, to port and"
|
|
||||||
3740 DATA "to starboard.", "", ""
|
|
||||||
3760 REM mid main corridor
|
|
||||||
3770 DATA "The main corridor stretches away from you both forward and aft. It is featureless"
|
|
||||||
3780 DATA "and utilitarian. The lighting is dim. You can see doors either side of you, to port and"
|
|
||||||
3790 DATA "to starboard.", "", ""
|
|
||||||
3810 REM forward main corridor
|
|
||||||
3820 DATA "The main corridor stretches away from you towards the rear of the ship. It is featureless"
|
|
||||||
3830 DATA "and utilitarian. The lighting is dim. You can see doors either side of you, to port and"
|
|
||||||
3840 DATA "to starboard, as well as a third door leading forward.", "", ""
|
|
||||||
3860 REM assign to room descriptions
|
|
||||||
3870 FOR ROOM = 0 to RC-1
|
|
||||||
3880 FOR I = 0 TO 4
|
|
||||||
3885 READ DESC$ : RD$ (ROOM, I) = DESC$
|
|
||||||
3890 NEXT I
|
|
||||||
3900 NEXT ROOM
|
|
||||||
4000 RETURN
|
|
||||||
4010 REM ========== print room description ==========
|
|
||||||
4020 FOR LINE = 0 TO 4
|
|
||||||
4030 IF RD$(PL, LINE) <> "" THEN PRINT RD$(PL, LINE)
|
|
||||||
4040 NEXT LINE
|
|
||||||
4055 GOSUB 4070
|
|
||||||
4060 RETURN
|
|
||||||
4070 REM print objects
|
|
||||||
4080 FOR I = 0 TO OC-1
|
|
||||||
4090 IF OL ( I ) = PL THEN PRINT : PRINT "You can see: ";OB$ ( I ); "."
|
|
||||||
4100 NEXT I
|
|
||||||
4110 PRINT
|
|
||||||
4115 IF PL = LAB THEN GOSUB 9700
|
|
||||||
4120 RETURN
|
|
||||||
4130 REM ========== print help ==========
|
|
||||||
4140 PRINT "For movement, try [go] a[ft], f[orward], p[ort], s[tarboard], u[p] or d[own]."
|
|
||||||
4150 PRINT "For actions, try get, take, drop, examine, look, use, i[nventory], q[uit]."
|
|
||||||
4155 PRINT "To examine, pick up, use or drop items, refer to them exactly as they are described."
|
|
||||||
4157 PRINT
|
|
||||||
4160 RETURN
|
|
||||||
5000 REM ========== interactive item descriptions ==========
|
|
||||||
5010 DIM ID$(IC, 20)
|
|
||||||
5020 REM medical log
|
|
||||||
5030 DATA "The last few entries of the medical log are still visible on the screen:", " "
|
|
||||||
5040 DATA "'2142-6-13: Three days since chimpanzee Nova was innoculated with agent #53."
|
|
||||||
5050 DATA " However, subject Nova showing no signs of adaptation to planetary destination"
|
|
||||||
5060 DATA " atmosphere. In fact, she appears listless, though punctuated with periods of"
|
|
||||||
5070 DATA " extreme agression.", " "
|
|
||||||
5090 DATA " 2142-6-14: This morning, Dr Pearson was bitten by Nova. Very quickly he exhibited"
|
|
||||||
5100 DATA " signs of a high fever and is now resting in his quarters.", " "
|
|
||||||
5120 DATA " 2142-6-15: After a brief period of catatonia, Pearson got up on his own, returned"
|
|
||||||
5130 DATA " to the medical bay and began to compulsively prepare more agent #53 samples. He"
|
|
||||||
5140 DATA " is otherwise uncommunicative.", " "
|
|
||||||
5160 DATA " 2142-6-17: Pearson's compulsive behaviour continues unabated. We have a hypothesis"
|
|
||||||
5170 DATA " for what the virus, which we have now designated HO-1, does to the brain. However,"
|
|
||||||
5180 DATA " we are struggling to isolate Pearson and may have to seal the medical bay.", " "
|
|
||||||
5200 DATA " 2142-6-17: Hollow (HO-1) confirmed as airborne, and other cases appearing around the ship."
|
|
||||||
5210 DATA " Shipwide lockdown declared but crew cohesion and discipline already breaking down.'"
|
|
||||||
5215 REM porthole
|
|
||||||
5220 DATA "Looking through the porthole, you seen a spacesuit clad figure floating outside."
|
|
||||||
5230 DATA "Although he is tethered to an anchor point on the ship's hull, he is otherwise floating"
|
|
||||||
5240 DATA "freely, his arms and legs splayed out to his sides.", " "
|
|
||||||
5260 DATA "Peering at the figure more closely, as he slowly rotates, a light from the ship"
|
|
||||||
5270 DATA "briefly illuminates his face. He's clearly dead, his oxygen ran out some time ago."
|
|
||||||
5280 DATA "His expression is frozen in a rictus of pain. He was screaming almost until the end ..."
|
|
||||||
5290 DATA "", "", "", "", "", "", "", "", "", "", "", "", ""
|
|
||||||
5300 REM console
|
|
||||||
5310 DATA "The console shows the state of the ship's engines. The pilot"
|
|
||||||
5320 DATA "appears to have the throttle jammed wide open with his right arm. The muscles in his"
|
|
||||||
5340 DATA "forearm are taught, there's no way he's going to release the throttle. He left hand"
|
|
||||||
5350 DATA "works its way around the console switches. After a few moments you realise that he is"
|
|
||||||
5360 DATA "executing the same sequence of switches over and over again.", " "
|
|
||||||
5370 DATA "His eyes are glazed, mentally he is somewhere else. He is"
|
|
||||||
5380 DATA "mumbling to himself but you cannot make out the words, although he appears to be"
|
|
||||||
5390 DATA "reciting some sort of launch checklist.", " "
|
|
||||||
5392 DATA "One screen shows the mission parameters:"
|
|
||||||
5394 DATA " 1. Explore potentially habitable worlds"
|
|
||||||
5396 DATA " 2. Conduct research to develop gene therapies to aid adaptation to planetary conditions"
|
|
||||||
5398 DATA " 3. Conduct research to develop custom biologic weapons systems, to protect colonists", " "
|
|
||||||
5400 DATA "If the engines are online, the ship will be careering through space at maximum"
|
|
||||||
5410 DATA "speed. Rescue will be impossible unless the engines are offline."
|
|
||||||
5420 DATA "", "", ""
|
|
||||||
5430 REM engine control
|
|
||||||
5440 DATA "The control panel is grubby, smeared with oil and grime. This is clearly"
|
|
||||||
5450 DATA "the engineering heart of the ship. Most of the readouts mean nothing to you,"
|
|
||||||
5460 DATA "whatever your duties were on this ship, you were clearly not a warp engineer.", " "
|
|
||||||
5470 DATA "Many of the lights on the front panel are flashing red. Not all is well with"
|
|
||||||
5480 DATA "the Pneuma. Even to your untrained eye, it's obvious that the ship's engines appear to"
|
|
||||||
5490 DATA "be on the point of burnout, having been run at full capacity for many hours.", " "
|
|
||||||
5500 DATA "To the top left of the panel, a screen reads:", " "
|
|
||||||
5510 DATA "'WARNING: CORE BREACH IMMINENT'", " "
|
|
||||||
5520 DATA "Just below the screen is a large red button, shielded by a cover that can be"
|
|
||||||
5530 DATA "flipped aside.", "", "", "", "", "", ""
|
|
||||||
5540 REM library terminal
|
|
||||||
5550 DATA "A ancient text is open in the terminal: 'The Origin of Consciousness in the Breakdown"
|
|
||||||
5560 DATA "of the Bicameral Mind by Julian Jaynes, 1976.'", "", "", "", "", "", "", "", "", ""
|
|
||||||
5570 DATA "", "", "", "", "", "", "", "", ""
|
|
||||||
5940 FOR OBJECT = 0 TO IC-1
|
|
||||||
5950 FOR I = 0 TO 19
|
|
||||||
5960 READ DESC$ : ID$ (OBJECT, I) = DESC$
|
|
||||||
5970 NEXT I
|
|
||||||
5980 NEXT OBJECT
|
|
||||||
5990 RETURN
|
|
||||||
6000 REM ========== print interative object description ==========
|
|
||||||
6010 FOR LINE = 0 TO 19
|
|
||||||
6020 IF ID$(F, LINE) <> "" THEN PRINT ID$(F, LINE)
|
|
||||||
6030 NEXT LINE
|
|
||||||
6035 PRINT
|
|
||||||
6040 RETURN
|
|
||||||
7000 REM ========== character speech ==========
|
|
||||||
7010 REM chef
|
|
||||||
7015 DIM PD$(PC, 4)
|
|
||||||
7020 DATA "Carrots, potatoes, I'm going to make a nice beef stew."
|
|
||||||
7030 DATA "This stew is going to be delicious."
|
|
||||||
7060 REM runner
|
|
||||||
7070 DATA "24:50, that's my new personal best. Not much further to go!"
|
|
||||||
7080 DATA "24:50, that's my new personal best. Not much further to go!"
|
|
||||||
7110 REM pilot
|
|
||||||
7120 DATA "Main engines online, supercruise on my mark."
|
|
||||||
7130 DATA "Five ... four ... three ... two ... one ... mark!"
|
|
||||||
7140 FOR PERSON = 0 TO PC-1
|
|
||||||
7150 FOR I = 0 TO 1
|
|
||||||
7160 READ DESC$ : PD$ (PERSON, I) = DESC$
|
|
||||||
7170 NEXT I
|
|
||||||
7180 PD$(PERSON, 2) = PD$(PERSON, 0)
|
|
||||||
7190 PD$(PERSON, 3) = PD$(PERSON, 1)
|
|
||||||
7200 NEXT PERSON
|
|
||||||
7210 RETURN
|
|
||||||
7500 REM ========== print character speech ==========
|
|
||||||
7510 FOR LINE = 0 TO 4
|
|
||||||
7520 PRINT PD$(F, LINE)
|
|
||||||
7530 NEXT LINE
|
|
||||||
7535 PRINT
|
|
||||||
7550 RETURN
|
|
||||||
8000 REM ========== wraith-hound tracking ==========
|
|
||||||
8010 IF OL ( TRACKER ) <> INV THEN RETURN
|
|
||||||
8015 IF WPL = 99 THEN PRINT "Tracking: Wraith-hound terminated." : GOTO 8030
|
|
||||||
8020 PRINT "Tracking: Wraith-hound current location is the "; LO$ ( WPL )
|
|
||||||
8030 PRINT
|
|
||||||
8040 RETURN
|
|
||||||
8200 REM ========== wraith-hound proximity check ==========
|
|
||||||
8210 DIR$ = ""
|
|
||||||
8220 IF VAL ( MID$ ( EX$ ( PL ) , 1 , 2 ) ) = WPL THEN DIR$ = "forward of you"
|
|
||||||
8230 IF VAL ( MID$ ( EX$ ( PL ) , 3 , 2 ) ) = WPL THEN DIR$ = "aft of you"
|
|
||||||
8240 IF VAL ( MID$ ( EX$ ( PL ) , 5 , 2 ) ) = WPL THEN DIR$ = "to port"
|
|
||||||
8250 IF VAL ( MID$ ( EX$ ( PL ) , 7 , 2 ) ) = WPL THEN DIR$ = "to starboard"
|
|
||||||
8260 IF VAL ( MID$ ( EX$ ( PL ) , 9 , 2 ) ) = WPL THEN DIR$ = "above you"
|
|
||||||
8270 IF VAL ( MID$ ( EX$ ( PL ) , 11 , 2 ) ) = WPL THEN DIR$ = "below you"
|
|
||||||
8280 IF DIR$ <> "" THEN PRINT "You hear a snarling, spitting noise "; DIR$; ". The tracker is pinging ..."
|
|
||||||
8285 PRINT
|
|
||||||
8290 RETURN
|
|
||||||
8400 REM ========== wraith-hound movement ==========
|
|
||||||
8410 REM decide to move one third of the time
|
|
||||||
8420 MOVE = RNDINT(1, 3)
|
|
||||||
8430 IF MOVE <> 1 THEN RETURN
|
|
||||||
8440 REM randomly determine direction
|
|
||||||
8450 DIR = RNDINT(1, 6)
|
|
||||||
8460 IF DIR = 1 THEN INDEX = 1
|
|
||||||
8470 IF DIR = 2 THEN INDEX = 3
|
|
||||||
8480 IF DIR = 3 THEN INDEX = 5
|
|
||||||
8490 IF DIR = 4 THEN INDEX = 7
|
|
||||||
8500 IF DIR = 5 THEN INDEX = 9
|
|
||||||
8510 IF DIR = 6 THEN INDEX = 11
|
|
||||||
8520 NWPL = VAL ( MID$ ( EX$ ( WPL ) , INDEX , 2 ) ) : REM potential next location
|
|
||||||
8530 IF NWPL = 0 THEN GOTO 8450 : REM can't go that way
|
|
||||||
8540 WPL = NWPL
|
|
||||||
8550 RETURN
|
|
||||||
9000 REM ========== use an item ==========
|
|
||||||
9010 F=-1: R$=""
|
|
||||||
9020 R$ = MID$(LOWER$(I$), 5) : REM R$ is the requested object
|
|
||||||
9025 IF R$ <> "red button" THEN GOTO 9030
|
|
||||||
9027 GOSUB 9500
|
|
||||||
9028 RETURN
|
|
||||||
9030 REM get the object ID
|
|
||||||
9040 FOR I= 0 TO OC-1
|
|
||||||
9050 IF OB$(I) = R$ THEN F=I : REM object exists
|
|
||||||
9060 NEXT I
|
|
||||||
9070 REM can't find the item?
|
|
||||||
9080 IF F=-1 THEN PRINT "You haven't seen that item." : PRINT : RETURN
|
|
||||||
9090 IF OL(F) <> 0 THEN PRINT "You haven't picked up that item." : PRINT : RETURN
|
|
||||||
9100 REM item exists and is in inventory
|
|
||||||
9110 IF F <> SYRINGE THEN GOTO 9140
|
|
||||||
9112 IF OB$( SYRINGE ) = "blood filled syringe" THEN PRINT "The syringe is full." : PRINT : RETURN
|
|
||||||
9115 IF SUIT_WORN = 1 THEN PRINT "You can't puncture a spacesuit with a syringe!" : PRINT : RETURN
|
|
||||||
9120 OB$( SYRINGE ) = "blood filled syringe"
|
|
||||||
9130 PRINT "You use the syringe to take a blood sample from your arm." : PRINT : RETURN
|
|
||||||
9140 IF F <> TRACKER THEN GOTO 9160
|
|
||||||
9150 PRINT "The tracker is always on." : PRINT
|
|
||||||
9160 IF F <> SUIT THEN GOTO 9200
|
|
||||||
9170 IF OL(F) <> 0 THEN PRINT "You don't have a space suit." : PRINT : RETURN
|
|
||||||
9175 IF SUIT_WORN = 1 THEN PRINT "You're already wearing the space suit." : PRINT : RETURN
|
|
||||||
9180 SUIT_WORN = 1
|
|
||||||
9190 PRINT "You put on the space suit." : PRINT
|
|
||||||
9400 RETURN
|
|
||||||
9500 REM special button routine
|
|
||||||
9510 IF PL <> ENG THEN PRINT "There is no red button here." : PRINT : RETURN
|
|
||||||
9520 IF SHUTDOWN = 0 THEN GOTO 9540
|
|
||||||
9525 SHUTDOWN = 0
|
|
||||||
9530 PRINT "Engine restart initiated ... engines online." : PRINT
|
|
||||||
9535 ID$ (ENGINE, 10) = "'WARNING: CORE BREACH IMMINENT'" : RETURN
|
|
||||||
9540 SHUTDOWN = 1
|
|
||||||
9550 PRINT "Engine shutdown initiated ... engines offline." : PRINT
|
|
||||||
9555 ID$ (ENGINE, 10) = "'ENGINES OFFLINE'"
|
|
||||||
9560 RETURN
|
|
||||||
9700 REM ========== laboratory conversation ==========
|
|
||||||
9710 PRINT "Dr Lascoe is stood in the laboratory. He is armed. He speaks to you." : PRINT
|
|
||||||
9720 PRINT "'It's you! You were infected with HO-1, but you seem to be normal."
|
|
||||||
9730 PRINT " Hollow destroys consciousness, it shuts down all self awareness in the brain."
|
|
||||||
9740 PRINT " The patient still functions to a degree, but they're an automaton, endlessly"
|
|
||||||
9750 PRINT " running the same mental subroutines like a piece of clockwork until the body"
|
|
||||||
9760 PRINT " breaks down.'" : PRINT
|
|
||||||
9770 PRINT "'I've been hiding in here to avoid contagion. Someone released the wraith-hound"
|
|
||||||
9780 PRINT " from containment, but I've been able to keep it away with this weapon."
|
|
||||||
9790 PRINT " But if you're immune, I can develop a vaccine from your blood.'" : PRINT
|
|
||||||
9800 IF OL(SYRINGE) = 0 AND OB$(SYRINGE) = "blood filled syringe" THEN GOTO 9820
|
|
||||||
9810 PRINT "'You need to get me a sample of your blood.'" : PRINT : RETURN
|
|
||||||
9820 PRINT "'Ah, I see you have a blood sample, excellent.'" : PRINT
|
|
||||||
9830 IF SUIT_WORN = 1 THEN GOTO 9855
|
|
||||||
9840 PRINT " I still don't want to take the risk that you are contagious. Put on a space"
|
|
||||||
9850 PRINT " suit and then I'll let you approach me.'" : PRINT: RETURN
|
|
||||||
9855 PRINT "'Good, you're wearing a suit to avoid contaminating me.'" : PRINT
|
|
||||||
9860 IF SHUTDOWN = 1 THEN GOTO 9885
|
|
||||||
9870 PRINT "'Rescue will be impossible while the engines are running out of control."
|
|
||||||
9880 PRINT " You'll need to take them offline.'": PRINT : RETURN
|
|
||||||
9885 PRINT "'Good job on taking the engines offline, you've saved us both!"
|
|
||||||
9890 PRINT " I'll work up the serum and we can wait for rescue.'" : PRINT
|
|
||||||
9900 GOSUB 10000
|
|
||||||
9910 RETURN
|
|
||||||
10000 REM ========== finale ==========
|
|
||||||
10010 PRINT "Congratulations, you have save Pneuma and helped Dr Lascoe develop"
|
|
||||||
10020 PRINT "vaccine against HO-1, the Hollow virus."
|
|
||||||
10030 PRINT : PRINT " THE END" : PRINT
|
|
||||||
10040 STOP
|
|
||||||
11000 REM ========== fight ==========
|
|
||||||
11010 PRINT "The wraith-hound arrives. It is an abomination! A weapon system that"
|
|
||||||
11020 PRINT "nature would never have created unaided. Everything about it is just"
|
|
||||||
11030 PRINT "plain wrong on so many levels. One thing is clear, it is designed"
|
|
||||||
11035 PRINT "purely for hunting and killing." : PRINT
|
|
||||||
11040 INPUT "Do you r[un] or f[ight]?"; I$
|
|
||||||
11050 PRINT
|
|
||||||
11060 IF LOWER$ ( I$ ) = "f" OR LOWER$ ( I$ ) = "fight" THEN GOTO 11190
|
|
||||||
11065 IF LOWER$ ( I$ ) = "r" OR LOWER$ ( I$ ) = "run" THEN GOTO 11070
|
|
||||||
11067 PRINT "Command unrecognised, you must fight!" : PRINT : GOTO 11190
|
|
||||||
11070 REM run away to a random adjoining room
|
|
||||||
11080 DIR = RNDINT(1, 6)
|
|
||||||
11090 IF DIR = 1 THEN INDEX = 1
|
|
||||||
11100 IF DIR = 2 THEN INDEX = 3
|
|
||||||
11110 IF DIR = 3 THEN INDEX = 5
|
|
||||||
11120 IF DIR = 4 THEN INDEX = 7
|
|
||||||
11130 IF DIR = 5 THEN INDEX = 9
|
|
||||||
11140 IF DIR = 6 THEN INDEX = 11
|
|
||||||
11150 NPL = VAL ( MID$ ( EX$ ( PL ) , INDEX , 2 ) ) : REM potential next location
|
|
||||||
11160 IF NPL = 0 THEN GOTO 11080 : REM can't go that way
|
|
||||||
11170 PL = NPL : PRINT "You are in the " ; LO$ ( PL ) : PRINT
|
|
||||||
11175 GOSUB 4010
|
|
||||||
11180 RETURN
|
|
||||||
11190 REM fight
|
|
||||||
11200 FEROCITY = 60 : REM ferocity factor for wraith-hound
|
|
||||||
11205 STAMINA = 50 : REM your stamina
|
|
||||||
11210 IF OL(PULSE) <> INV AND OL(KNIFE) <> INV THEN PRINT "You have no weapons, and must fight bare handed." : PRINT : GOTO 11280
|
|
||||||
11220 IF OL(PULSE) = INV AND OL(KNIFE) <> INV THEN PRINT "Luckily, you have a pulse rifle." : PRINT: FEROCITY=50 : GOTO 11280
|
|
||||||
11230 IF OL(PULSE) <> INV AND OL(KNIFE) = INV THEN PRINT "You only have a knife with which to fight." : PRINT : FEROCITY = 55 : GOTO 11280
|
|
||||||
11240 INPUT "Which weapon do you choose? 1 - Pulse rifle, 2 - Knife: "; WPN
|
|
||||||
11245 PRINT
|
|
||||||
11250 IF WPN<1 OR WPN>2 THEN GOTO 11240
|
|
||||||
11260 IF WPN=1 THEN FEROCITY = 50
|
|
||||||
11270 IF WPN=2 THEN FEROCITY = 55
|
|
||||||
11280 REM the battle
|
|
||||||
11290 IF RND(1)>0.5 THEN PRINT "The wraith-hound attacks!" ELSE PRINT "You attack!"
|
|
||||||
11300 PRINT
|
|
||||||
11305 GOSUB 11430
|
|
||||||
11310 IF RND(1)>0.5 THEN PRINT "You wound the creature." : PRINT: FEROCITY = FEROCITY-5 : GOTO 11330
|
|
||||||
11320 PRINT "The wraith-hound wounds you." : PRINT : STAMINA = STAMINA-5
|
|
||||||
11330 GOSUB 11430
|
|
||||||
11340 IF FEROCITY > 0 THEN GOTO 11390
|
|
||||||
11350 PRINT "You slayed the wraith-hound!" : PRINT
|
|
||||||
11360 REM remove creature from the game
|
|
||||||
11370 WPL = 99 : REM inaccessible location
|
|
||||||
11380 RETURN
|
|
||||||
11390 IF STAMINA > 0 THEN GOTO 11420
|
|
||||||
11400 PRINT "You were slayed by the wraith-hound! You have failed to save the Pneuma." : PRINT
|
|
||||||
11410 STOP
|
|
||||||
11420 GOTO 11280 : REM next round of the battle
|
|
||||||
11430 REM ========== delay loop ==========
|
|
||||||
11440 FOR T = 1 TO 80000
|
|
||||||
11450 NEXT T
|
|
||||||
11460 RETURN
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,682 +0,0 @@
|
||||||
520 REM
|
|
||||||
530 REM
|
|
||||||
540 REM **** **** STAR TREK **** ****
|
|
||||||
550 REM **** Simulation of a mission of the starship ENTERPRISE
|
|
||||||
560 REM **** as seen on the Star Trek tv show
|
|
||||||
570 REM **** Original program in Creative Computing
|
|
||||||
580 REM **** Basic Computer Games by Dave Ahl
|
|
||||||
590 REM **** Modifications by Bob Fritz and Sharon Fritz
|
|
||||||
600 REM **** for the IBM Personal Computer, October-November 1981
|
|
||||||
610 REM **** Bob Fritz, 9915 Caninito Cuadro, San Diego, Ca., 92129
|
|
||||||
620 REM **** (714) 484-2955
|
|
||||||
630 REM ****
|
|
||||||
640 PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT
|
|
||||||
650 E1$= " ,-----------------, _"
|
|
||||||
660 E2$= " `---------- ----',-----/ \----,"
|
|
||||||
670 E3$= " | | '- --------'"
|
|
||||||
680 E4$= " ,--' '------/ /--,"
|
|
||||||
690 E5$= " '-----------------'"
|
|
||||||
691 PRINT
|
|
||||||
700 E6$= " THE USS ENTERPRISE --- NCC-1701"
|
|
||||||
720 PRINT E1$
|
|
||||||
730 PRINT E2$
|
|
||||||
740 PRINT E3$
|
|
||||||
750 PRINT E4$
|
|
||||||
760 PRINT E5$
|
|
||||||
770 PRINT
|
|
||||||
780 PRINT E6$
|
|
||||||
790 PRINT:PRINT: PRINT:PRINT:PRINT:PRINT:PRINT
|
|
||||||
811 RANDOMIZE
|
|
||||||
960 dim D(8)
|
|
||||||
961 dim C(9,2)
|
|
||||||
962 dim K(3,3)
|
|
||||||
963 dim N(3)
|
|
||||||
965 DIM G(8,8)
|
|
||||||
966 DIM Z(8,8)
|
|
||||||
970 T=INT(RND(1)*20+20)*100:T0=T:T9=25+INT(RND(1)*10):D0=0:E=3000:E0=E
|
|
||||||
980 P=10:P0=P:S9=200:S=0:B9=0:K9=0:X$="":X0$=" is "
|
|
||||||
990 rem DEF FND(D)=SQR((K(I,1)-S1)^2+(K(I,2)-S2)^2)
|
|
||||||
1000 rem DEF FNR(R)=INT(RND(1)(R)*7.98+1.01)
|
|
||||||
1010 REM initialize enterprise's position
|
|
||||||
1020 Q1=INT(RND(1)*7.98+1.01):Q2=INT(RND(1)*7.98+1.01):S1=INT(RND(1)*7.98+1.01):S2=INT(RND(1)*7.98+1.01)
|
|
||||||
1030 FOR I=1 TO 9
|
|
||||||
1031 C(I,1)=0:C(I,2)=0
|
|
||||||
1032 NEXT I
|
|
||||||
1040 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1
|
|
||||||
1050 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1
|
|
||||||
1060 FOR I=1 TO 8
|
|
||||||
1061 D(I)=0
|
|
||||||
1062 NEXT I
|
|
||||||
1070 A1$="NAVSRSLRSPHATORSHIDAMCOMRES"
|
|
||||||
1080 REM set up what exists in galaxy
|
|
||||||
1090 REM k3=#klingons b3=#starbases s3=#stars
|
|
||||||
1100 FOR I=1 TO 8
|
|
||||||
1101 FOR J=1 TO 8
|
|
||||||
1102 K3=0:Z(I,J)=0:R1=RND(1)
|
|
||||||
1110 IF R1<=0.9799999 THEN goto 1120
|
|
||||||
1111 K3=3:K9=K9+3: GOTO 1140
|
|
||||||
1120 IF R1<=0.95 THEN goto 1130
|
|
||||||
1121 K3=2:K9=K9+2: GOTO 1140
|
|
||||||
1130 IF R1<=0.8 THEN goto 1140
|
|
||||||
1131 K3=1:K9=K9+1
|
|
||||||
1140 B3=0:IF RND(1)<=0.96 THEN goto 1150
|
|
||||||
1141 B3=1:B9=B9+1
|
|
||||||
1150 G(I,J)=K3*100+B3*10+INT(RND(1)*7.98+1.01)
|
|
||||||
1151 NEXT J
|
|
||||||
1152 NEXT I
|
|
||||||
1153 IF K9<=T9 THEN goto 1160
|
|
||||||
1154 T9=K9+1
|
|
||||||
1160 IF B9<>0 THEN 1190
|
|
||||||
1170 IF G(Q1,Q2)>=200 THEN 1180
|
|
||||||
1171 G(Q1,Q2)=G(Q1,Q2)+100:K9=K9+1
|
|
||||||
1180 B9=1:G(Q1,Q2)=G(Q1,Q2)+10:Q1=INT(RND(1)*7.98+1.01):Q2=INT(RND(1)*7.98+1.01)
|
|
||||||
1190 K7=K9:IF B9=1 THEN 1200
|
|
||||||
1191 X$="s":X0$=" are "
|
|
||||||
1200 PRINT" Your orders are as follows: "
|
|
||||||
1210 PRINT" Destroy the ";K9;" Klingon warships which have invaded"
|
|
||||||
1220 PRINT" the galaxy before they can attack Federation headquarters"
|
|
||||||
1230 PRINT" on stardate ";T0+T9;". This gives you ";T9;" days. there";X0$
|
|
||||||
1240 PRINT" ";B9;" starbase";X$;" in the galaxy for resupplying your ship"
|
|
||||||
1261 PRINT:INPUT"hit return when ready to accept command";i$
|
|
||||||
1270 REM here any time new quadrant entered
|
|
||||||
1280 Z4=Q1:Z5=Q2:K3=0:B3=0:S3=0:G5=0:D4=0.5*RND(1):Z(Q1,Q2)=G(Q1,Q2)
|
|
||||||
1290 IF Q1<1 OR Q1>8 OR Q2<1 OR Q2>8 THEN 1410
|
|
||||||
1300 GOSUB 5040
|
|
||||||
1301 PRINT:IF T0 <>T THEN 1330
|
|
||||||
1310 PRINT"Your mission begins with your starship located"
|
|
||||||
1320 PRINT"in the galactic quadrant, '";G2$;"'.":GOTO 1340
|
|
||||||
1330 PRINT"Now entering ";G2$;" quadrant. . ."
|
|
||||||
1340 PRINT:K3=INT(G(Q1,Q2)*0.01):B3=INT(G(Q1,Q2)*0.1)-10*K3
|
|
||||||
1350 S3=G(Q1,Q2)-100*K3-10*B3:IF K3=0 THEN 1400
|
|
||||||
1360 PRINT "COMBAT AREA!! Condition";
|
|
||||||
1370 PRINT " RED "; : PRINT
|
|
||||||
1380 GOSUB 5290
|
|
||||||
1381 IF S>200 THEN 1400
|
|
||||||
1390 PRINT" SHIELDS DANGEROUSLY LOW"; : PRINT
|
|
||||||
1400 FOR I=1 TO 3
|
|
||||||
1401 K(I,1)=0:K(I,2)=0
|
|
||||||
1402 NEXT I
|
|
||||||
1410 FOR I=1 TO 3
|
|
||||||
1411 K(I,3)=0
|
|
||||||
1412 NEXT I
|
|
||||||
1413 Q$=" "*192
|
|
||||||
1420 REM position enterprise in quadrant, then place "k3" klingons,&
|
|
||||||
1430 REM "b3" starbases & "s3" stars elsewhere.
|
|
||||||
1440 A$="\e/":Z1=S1:Z2=S2
|
|
||||||
1441 GOSUB 4830
|
|
||||||
1442 IF K3<1 THEN 1470
|
|
||||||
1450 FOR I=1 TO K3
|
|
||||||
1451 GOSUB 4800
|
|
||||||
1452 A$=chr$(187)+"K"+chr$(171):Z1=R1:Z2=R2
|
|
||||||
1460 GOSUB 4830
|
|
||||||
1461 K(I,1)=R1:K(I,2)=R2:K(I,3)=S9*(0.5+RND(1))
|
|
||||||
1462 NEXT I
|
|
||||||
1470 IF B3<1 THEN 1500
|
|
||||||
1480 GOSUB 4800
|
|
||||||
1481 A$="("+chr$(174)+")":Z1=R1:B4=R1:Z2=R2:B5=R2
|
|
||||||
1490 GOSUB 4830
|
|
||||||
1500 FOR I=1 TO S3
|
|
||||||
1501 GOSUB 4800
|
|
||||||
1502 A$=" * ":Z1=R1:Z2=R2
|
|
||||||
1503 GOSUB 4830
|
|
||||||
1504 NEXT I
|
|
||||||
1510 GOSUB 3720
|
|
||||||
1520 IF S+E<=10 THEN 1530
|
|
||||||
1521 IF E>10 OR D(7)>=0 THEN 1580
|
|
||||||
1530 PRINT"*** FATAL ERROR ***";
|
|
||||||
1531 GOSUB 5290
|
|
||||||
1540 PRINT"You've just stranded your ship in "
|
|
||||||
1550 PRINT"space":PRINT"You have insufficient maneuvering energy,";
|
|
||||||
1560 PRINT" and shield control":PRINT"is presently incapable of cross";
|
|
||||||
1570 PRINT"-circuiting to engine room!!":GOTO 3480
|
|
||||||
1580 INPUT"command ";A$
|
|
||||||
1590 FOR I=1 TO 9
|
|
||||||
1591 IF MID$(A$,1,3)<> MID$(A1$,3*I-2,3) THEN 1610
|
|
||||||
1600 ON I GOTO 1720,1510,2440,2530,2750,3090,3180,3980,3510
|
|
||||||
1610 NEXT I
|
|
||||||
1611 PRINT"Enter one of the following:"
|
|
||||||
1620 PRINT" NAV (to set course)"
|
|
||||||
1630 PRINT" SRS (for short range sensor scan)"
|
|
||||||
1640 PRINT" LRS (for long range sensor scan)"
|
|
||||||
1650 PRINT" PHA (to fire phasers)"
|
|
||||||
1660 PRINT" TOR (to fire photon torpedoes)"
|
|
||||||
1670 PRINT" SHI (to raise or lower shields)"
|
|
||||||
1680 PRINT" DAM (for damage control reports)"
|
|
||||||
1690 PRINT" COM (to call on library-computer)"
|
|
||||||
1700 PRINT" RES (to resign your command)":PRINT:GOTO 1520
|
|
||||||
1710 REM course control begins here
|
|
||||||
1720 INPUT"Course (1-9) ";C2$:C1=VAL(C2$):IF C1<>9 THEN 1730
|
|
||||||
1721 C1=1
|
|
||||||
1730 IF C1>=1 AND C1<9 THEN 1750
|
|
||||||
1740 PRINT" Lt. Sulu reports, 'Incorrect course data, sir!'":GOTO 1520
|
|
||||||
1750 X$="8":IF D(1)>=0 THEN 1760
|
|
||||||
1751 X$="0.2"
|
|
||||||
1760 PRINT"Warp factor(0-";X$;") ";:INPUT C2$:W1=VAL(C2$):IF D(1)<0 AND W1>0.2 THEN 1810
|
|
||||||
1770 IF W1>0 AND W1<8 THEN 1820
|
|
||||||
1780 IF W1=0 THEN 1520
|
|
||||||
1790 PRINT" Chief Engineer Scott reports 'The engines won't take";
|
|
||||||
1800 PRINT" warp ";W1;"!":GOTO 1520
|
|
||||||
1810 PRINT"Warp engines are damaged. Maximum speed = warp 0.2":GOTO 1520
|
|
||||||
1820 N1=INT(W1*8+0.5):IF E-N1>=0 THEN 1900
|
|
||||||
1830 PRINT"Engineering reports 'Insufficient energy available"
|
|
||||||
1840 PRINT" for maneuvering at warp ";W1;"!'"
|
|
||||||
1850 IF S<N1-E OR D(7)<0 THEN 1520
|
|
||||||
1860 PRINT"Deflector control room acknowledges ";S;" units of energy"
|
|
||||||
1870 PRINT" presently deployed to shields."
|
|
||||||
1880 GOTO 1520
|
|
||||||
1890 REM klingons move/fire on moving starship . . .
|
|
||||||
1900 FOR I=1 TO K3
|
|
||||||
1901 IF K(I,3)=0 THEN 1930
|
|
||||||
1910 A$=" ":Z1=K(I,1):Z2=K(I,2)
|
|
||||||
1911 GOSUB 4830
|
|
||||||
1912 GOSUB 4800
|
|
||||||
1920 K(I,1)=Z1:K(I,2)=Z2:A$=chr$(187)+"K"+chr$(171)
|
|
||||||
1921 GOSUB 4830
|
|
||||||
1930 NEXT I
|
|
||||||
1931 REM GOSUB 4810
|
|
||||||
1932 D1=0:D6=W1:IF W1<1 THEN 1940
|
|
||||||
1933 D6=1
|
|
||||||
1940 FOR I=1 TO 8
|
|
||||||
1941 IF D(I)>=0 THEN 1990
|
|
||||||
1950 D(I)=min(0,D(I)+D6):IF D(I)<=-0.1 or D(I)>=0 THEN 1960
|
|
||||||
1951 D(I)=-0.1
|
|
||||||
1952 GOTO 1990
|
|
||||||
1960 IF D(I)<0 THEN 1990
|
|
||||||
1970 IF D1=1 THEN 1980
|
|
||||||
1971 D1=1:PRINT"DAMAGE CONTROL REPORT: ";
|
|
||||||
1980 PRINT TAB(8);:R1=I
|
|
||||||
1981 GOSUB 4890
|
|
||||||
1982 PRINT G2$;" Repair completed."
|
|
||||||
1990 NEXT I
|
|
||||||
1991 IF RND(1)>0.2 THEN 2070
|
|
||||||
2000 R1=INT(RND(1)*7.98+1.01):IF RND(1)>=0.6 THEN 2040
|
|
||||||
2010 IF K3=0 THEN 2070
|
|
||||||
2020 D(R1)=D(R1)-(RND(1)*5+1):PRINT"DAMAGE CONTROL REPORT: ";
|
|
||||||
2030 GOSUB 4890
|
|
||||||
2031 PRINT G2$;" damaged":PRINT:GOTO 2070
|
|
||||||
2040 D(R1)=min(0,D(R1)+RND(1)*3+1):PRINT"DAMAGE CONTROL REPORT: ";
|
|
||||||
2050 GOSUB 4890
|
|
||||||
2051 PRINT G2$;" State of repair improved":PRINT
|
|
||||||
2060 REM begin moving starship
|
|
||||||
2070 A$=" " :Z1=INT(S1):Z2=INT(S2)
|
|
||||||
2071 GOSUB 4830
|
|
||||||
2079 Z1=INT(C1):C1=C1-Z1
|
|
||||||
2080 X1=C(Z1,1)+(C(Z1+1,1)-C(Z1,1))*C1:X=S1:Y=S2
|
|
||||||
2090 X2=C(Z1,2)+(C(Z1+1,2)-C(Z1,2))*C1:Q4=Q1:Q5=Q2
|
|
||||||
2100 FOR I=1 TO N1
|
|
||||||
2101 S1=S1+X1:S2=S2+X2:IF S1<1 OR S1>=9 OR S2<1 OR S2>=9 THEN 2220
|
|
||||||
2110 S8=INT(S1)*24+INT(S2)*3-26:IF MID$(Q$,S8+1,2)=" " THEN 2140
|
|
||||||
2120 S1=INT(S1-X1):S2=INT(S2-X2):PRINT"Warp engines shut down at ";
|
|
||||||
2130 PRINT "sector ";S1;",";S2;" due to bad navigation.":GOTO 2150
|
|
||||||
2140 NEXT I
|
|
||||||
2141 S1=INT(S1):S2=INT(S2)
|
|
||||||
2150 A$="\e/"
|
|
||||||
2160 Z1=INT(S1):Z2=INT(S2)
|
|
||||||
2161 GOSUB 4830
|
|
||||||
2162 GOSUB 2390
|
|
||||||
2163 T8=1
|
|
||||||
2170 IF W1>=1 THEN 2180
|
|
||||||
2171 T8=0.1*INT(10*W1)
|
|
||||||
2180 T=T+T8:IF T>T0+T9 THEN 3480
|
|
||||||
2190 REM see if docked then get command
|
|
||||||
2200 GOTO 1510
|
|
||||||
2210 REM exceeded quadrant limits
|
|
||||||
2220 X=8*Q1+X+N1*X1:Y=8*Q2+Y+N1*X2:Q1=INT(X/8):Q2=INT(Y/8):S1=INT(X-Q1*8)
|
|
||||||
2230 S2=INT(Y-Q2*8):IF S1<>0 THEN 2240
|
|
||||||
2231 Q1=Q1-1:S1=8
|
|
||||||
2240 IF S2<>0 THEN 2250
|
|
||||||
2241 Q2=Q2-1:S2=8
|
|
||||||
2250 X5=0:IF Q1>=1 THEN 2260
|
|
||||||
2251 X5=1:Q1=1:S1=1
|
|
||||||
2260 IF Q1<=8 THEN 2270
|
|
||||||
2261 X5=1:Q1=8:S1=8
|
|
||||||
2270 IF Q2>=1 THEN 2280
|
|
||||||
2271 X5=1:Q2=1:S2=1
|
|
||||||
2280 IF Q2<=8 THEN 2290
|
|
||||||
2281 X5=1:Q2=8:S2=8
|
|
||||||
2290 IF X5=0 THEN 2360
|
|
||||||
2300 PRINT"Lt. Uhura reports message from Starfleet Command:"
|
|
||||||
2310 PRINT" 'Permission to attempt crossing of galactic perimeter"
|
|
||||||
2320 PRINT" is hereby *DENIED*. Shut down your engines.'"
|
|
||||||
2330 PRINT"Chief Engineer Scott reports 'Warp engines shut down"
|
|
||||||
2340 PRINT" at sector ";S1;",";S2;" of quadrant ";Q1;",";Q2".'"
|
|
||||||
2350 IF T>T0 THEN 3480
|
|
||||||
2360 IF 8*Q1+Q2=8*Q4+Q5 THEN 2150
|
|
||||||
2370 T=T+1
|
|
||||||
2371 GOSUB 2390
|
|
||||||
2372 GOTO 1280
|
|
||||||
2380 REM maneuver energy s/r **
|
|
||||||
2390 E=E-N1-10:IF E<=0 THEN 2400
|
|
||||||
2391 RETURN
|
|
||||||
2400 PRINT"Shield control supplies energy to complete the maneuver."
|
|
||||||
2410 S=S+E:E=0:IF S<=0 THEN 2420
|
|
||||||
2411 S=0
|
|
||||||
2420 RETURN
|
|
||||||
2430 REM long range sensor scan code
|
|
||||||
2440 IF D(3)>=0 THEN 2450
|
|
||||||
2441 PRINT"Long Range Sensors are inoperable":GOTO 1520
|
|
||||||
2450 PRINT"Long Range Scan for quadrant ";Q1;",";Q2
|
|
||||||
2460 PRINT "-"*19
|
|
||||||
2470 FOR I=Q1-1 TO Q1+1
|
|
||||||
2471 N(1)=-1:N(2)=-2:N(3)=-3
|
|
||||||
2472 FOR J=Q2-1 TO Q2+1
|
|
||||||
2480 IF I<=0 or I>=9 or J<=0 or J>=9 THEN 2490
|
|
||||||
2481 N(J-Q2+2)=G(I,J)
|
|
||||||
2482 REM added so long range sensor scans are added to computer database
|
|
||||||
2483 z(i,j)=g(i,j)
|
|
||||||
2490 NEXT J
|
|
||||||
2491 FOR L=1 TO 3
|
|
||||||
2492 PRINT"| ";
|
|
||||||
2493 IF N(L)>=0 THEN 2500
|
|
||||||
2494 PRINT"*** ";:GOTO 2510
|
|
||||||
2500 PRINT MID$(STR$(N(L)+1000),2,3);" ";
|
|
||||||
2510 NEXT L
|
|
||||||
2511 PRINT"|"
|
|
||||||
2512 PRINT "-"*19
|
|
||||||
2513 NEXT I
|
|
||||||
2514 GOTO 1520
|
|
||||||
2520 REM phaser control code begins here
|
|
||||||
2530 IF D(4)>=0 THEN 2540
|
|
||||||
2531 PRINT"Phasers Inoperative":GOTO 1520
|
|
||||||
2540 IF K3>0 THEN 2570
|
|
||||||
2550 PRINT"Science Officer Spock reports 'Sensors show no enemy ships"
|
|
||||||
2560 PRINT" in this quadrant'":GOTO 1520
|
|
||||||
2570 IF D(8)>=0 THEN 2580
|
|
||||||
2571 PRINT"Computer failure hampers accuracy"
|
|
||||||
2580 PRINT"Phasers locked on target ";
|
|
||||||
2590 PRINT"Energy available = ";E;" units"
|
|
||||||
2600 INPUT"Numbers of units to fire ";X:IF X<=0 THEN 1520
|
|
||||||
2610 IF E-X<0 THEN 2590
|
|
||||||
2620 E=E-X
|
|
||||||
2621 GOSUB 5420
|
|
||||||
2622 IF D(7)<0 THEN 2630
|
|
||||||
2623 X=X*RND(1)
|
|
||||||
2630 H1=INT(X/K3)
|
|
||||||
2631 FOR I=1 TO 3
|
|
||||||
2632 IF K(I,3)<=0 THEN 2730
|
|
||||||
2640 KSQ1 = (K(I,1)-S1)*(K(I,1)-S1)
|
|
||||||
2641 KSQ2 = (K(I,2)-S2)*(K(I,2)-S2)
|
|
||||||
2642 H= SQR( KSQ1 + KSQ2 )
|
|
||||||
2646 H = H1 / H
|
|
||||||
2647 H = INT(H * (RND(1)+2))
|
|
||||||
2648 IF H>0.15*K(I,3) THEN 2660
|
|
||||||
2650 PRINT"Sensors show no damage to enemy at ";K(I,1);",";K(I,2):GOTO 2730
|
|
||||||
2660 K(I,3)=K(I,3)-H:PRINT H;"Unit hit on Klingon at sector ";K(I,1);",";
|
|
||||||
2670 PRINT K(I,2):IF K(I,3)> 0 THEN GOTO 2700
|
|
||||||
2680 PRINT "**** KLINGON DESTROYED ****"
|
|
||||||
2690 GOTO 2710
|
|
||||||
2700 PRINT" (Sensors show ";K(I,3);" units remaining)":GOTO 2730
|
|
||||||
2710 K3=K3-1:K9=K9-1:Z1=K(I,1):Z2=K(I,2):A$=" "
|
|
||||||
2711 GOSUB 4830
|
|
||||||
2720 K(I,3)=0:G(Q1,Q2)=G(Q1,Q2)-100:Z(Q1,Q2)=G(Q1,Q2):IF K9<=0 THEN 3680
|
|
||||||
2730 NEXT I
|
|
||||||
2731 GOSUB 3350
|
|
||||||
2732 GOTO 1520
|
|
||||||
2740 REM photon torpedo code begins here
|
|
||||||
2750 IF P>0 THEN 2760
|
|
||||||
2751 PRINT"All photon torpedoes expended":GOTO 1520
|
|
||||||
2760 IF D(5)>=0 THEN 2770
|
|
||||||
2761 PRINT"Photon tubes are not operational":GOTO 1520
|
|
||||||
2770 INPUT"Photon torpedo course (1-9) ";C2$:C1=VAL(C2$):IF C1<>9 THEN 2780
|
|
||||||
2771 C1=1
|
|
||||||
2780 IF C1>=1 AND C1<9 THEN 2810
|
|
||||||
2790 PRINT"Ensign Chekov reports, 'Incorrect course data, sir!'"
|
|
||||||
2800 GOTO 1520
|
|
||||||
2810 Z1=INT(C1):C1=C1-Z1
|
|
||||||
2811 X1=C(Z1,1)+(C(Z1+1,1)-C(Z1,1))*C1:E=E-2:P=P-1
|
|
||||||
2820 X2=C(Z1,2)+(C(Z1+1,2)-C(Z1,2))*C1:X=S1:Y=S2
|
|
||||||
2821 GOSUB 5360
|
|
||||||
2830 PRINT"Torpedo track:"
|
|
||||||
2840 X=X+X1:Y=Y+X2:X3=INT(X+0.5):Y3=INT(Y+0.5)
|
|
||||||
2850 IF X3<1 OR X3>8 OR Y3<1 OR Y3>8 THEN 3070
|
|
||||||
2860 PRINT" ";X3;",";Y3:A$=" ":Z1=X:Z2=Y
|
|
||||||
2861 GOSUB 4990
|
|
||||||
2870 IF Z3<>0 THEN 2840
|
|
||||||
2880 A$=chr$(187)+"K"+chr$(171):Z1=X:Z2=Y
|
|
||||||
2881 GOSUB 4990
|
|
||||||
2882 IF Z3=0 THEN 2940
|
|
||||||
2890 PRINT"**** KLINGON DESTROYED ****"
|
|
||||||
2900 K3=K3-1:K9=K9-1:IF K9<=0 THEN 3680
|
|
||||||
2910 FOR I=1 TO 3
|
|
||||||
2911 IF X3=K(I,1) AND Y3=K(I,2) THEN 2930
|
|
||||||
2920 NEXT I
|
|
||||||
2921 I=3
|
|
||||||
2930 K(I,3)=0:GOTO 3050
|
|
||||||
2940 A$=" * ":Z1=X:Z2=Y
|
|
||||||
2941 GOSUB 4990
|
|
||||||
2942 IF Z3=0 THEN 2960
|
|
||||||
2950 PRINT"Star at ";X3;",";Y3;" absorbed torpedo energy."
|
|
||||||
2951 GOSUB 3350
|
|
||||||
2952 GOTO 1520
|
|
||||||
2960 A$="("+chr$(174)+")":Z1=X:Z2=Y
|
|
||||||
2961 GOSUB 4990
|
|
||||||
2962 IF Z3<>0 THEN 2970
|
|
||||||
2963 PRINT "Torpedo absorbed by unknown object at ";x3;",";y3
|
|
||||||
2964 goto 1520
|
|
||||||
2970 PRINT"*** STARBASE DESTROYED ***"
|
|
||||||
2980 B3=B3-1 : B9=B9-1
|
|
||||||
2990 IF B9>0 OR K9>T-T0-T9 THEN 3030
|
|
||||||
3000 PRINT"THAT DOES IT, CAPTAIN!! You are hereby relieved of command"
|
|
||||||
3010 PRINT"and sentenced to 99 stardates of hard labor on CYGNUS 12!!"
|
|
||||||
3020 GOTO 3510
|
|
||||||
3030 PRINT"Starfleet reviewing your record to consider"
|
|
||||||
3040 PRINT"court martial!":D0=0
|
|
||||||
3050 Z1=X:Z2=Y:A$=" "
|
|
||||||
3051 GOSUB 4830
|
|
||||||
3060 G(Q1,Q2)=K3*100+B3*10+S3:Z(Q1,Q2)=G(Q1,Q2)
|
|
||||||
3061 GOSUB 3350
|
|
||||||
3062 GOTO 1520
|
|
||||||
3070 PRINT"Torpedo missed"
|
|
||||||
3071 GOSUB 3350
|
|
||||||
3072 GOTO 1520
|
|
||||||
3080 REM shield control
|
|
||||||
3090 IF D(7)>=0 THEN 3100
|
|
||||||
3091 PRINT"Shield control inoperable":GOTO 1520
|
|
||||||
3100 PRINT"Energy available = ";E+S :INPUT "Number of units to shields? ";X
|
|
||||||
3110 IF X>=0 and S<>X THEN 3120
|
|
||||||
3111 PRINT"<shields unchanged>":GOTO 1520
|
|
||||||
3120 IF X<E+S THEN 3150
|
|
||||||
3130 PRINT"Shield Control reports: This is not the federation treasury."
|
|
||||||
3140 PRINT"<shields unchanged>":goto 1990
|
|
||||||
3150 E=E+S-X:S=X:PRINT"Deflector Control Room report:"
|
|
||||||
3160 PRINT" 'Shields now at ";INT(S);" units per your command.'":GOTO 1520
|
|
||||||
3170 REM damage control
|
|
||||||
3180 IF D(6)>=0 THEN 3290
|
|
||||||
3190 PRINT"Damage control report not available":IF D0=0 THEN 1520
|
|
||||||
3200 D3=0:FOR I=1 TO 8
|
|
||||||
3201 IF D(I)>=0 THEN 3210
|
|
||||||
3202 D3=D3+1
|
|
||||||
3210 NEXT I
|
|
||||||
3211 IF D3=0 THEN 1520
|
|
||||||
3220 PRINT:D3=D3+D4:IF D3<1 THEN 3230
|
|
||||||
3221 D3=0.9
|
|
||||||
3230 PRINT"Technicians standing by to effect repairs to your ship;"
|
|
||||||
3240 PRINT"estimated time to repair: ";0.01*INT(100*D3);" stardates"
|
|
||||||
3250 INPUT"Will you authorize the repair order (Y/N)? ";A$
|
|
||||||
3260 IF A$<>"y" AND A$<> "Y" THEN 1520
|
|
||||||
3270 FOR I=1 TO 8
|
|
||||||
3271 IF D(I)>=0 THEN 3280
|
|
||||||
3272 D(I)=0
|
|
||||||
3280 NEXT I
|
|
||||||
3281 T=T+D3+0.1
|
|
||||||
3290 PRINT:PRINT"Device state of repair"
|
|
||||||
3291 FOR R1=1 TO 8
|
|
||||||
3300 GOSUB 4890
|
|
||||||
3301 PRINT G2$;tab(25);
|
|
||||||
3310 GG2=INT(D(R1)*100)*0.01:PRINT GG2
|
|
||||||
3320 NEXT R1
|
|
||||||
3321 PRINT:IF D0<>0 THEN 3200
|
|
||||||
3330 GOTO 1520
|
|
||||||
3340 REM klingons shooting
|
|
||||||
3350 IF K3>0 THEN 3360
|
|
||||||
3351 RETURN
|
|
||||||
3360 IF D0=0 THEN 3370
|
|
||||||
3361 PRINT"Starbase shields protect the ENTERPRISE"
|
|
||||||
3362 RETURN
|
|
||||||
3370 FOR I=1 TO 3
|
|
||||||
3371 IF K(I,3)<=0 THEN 3460
|
|
||||||
3380 ksq1 = (K(I,1)-S1)*(K(I,1)-S1)
|
|
||||||
3381 ksq2 = (K(I,2)-S2)*(K(I,2)-S2)
|
|
||||||
3382 H=( K(I,3) / SQR( ksq1 + ksq2 ) )*(2+RND(1))
|
|
||||||
3383 h = int(h)
|
|
||||||
3384 S=S-H:K(I,3)=K(I,3)/(3+RND(1))
|
|
||||||
3390 PRINT "ENTERPRISE HIT!"
|
|
||||||
3400 GOSUB 5480
|
|
||||||
3401 PRINT H;" Unit hit on ENTERPRISE from sector ";K(I,1);",";K(I,2)
|
|
||||||
3410 IF S<=0 THEN 3490
|
|
||||||
3420 PRINT" <shields down to ";S;" units>":IF H<20 THEN 3460
|
|
||||||
3430 IF RND(1)>0.6 OR H/S<=0.02 THEN 3460
|
|
||||||
3440 R1=INT(RND(1)*7.98+1.01):D(R1)=D(R1)-H/S-0.5*RND(1)
|
|
||||||
3441 GOSUB 4890
|
|
||||||
3450 PRINT"Damage control reports '";G2$;" damaged by the hit'"
|
|
||||||
3460 NEXT I
|
|
||||||
3461 RETURN
|
|
||||||
3470 REM end of game
|
|
||||||
3480 PRINT"It is stardate";T:GOTO 3510
|
|
||||||
3490 PRINT:PRINT"the ENTERPRISE has been destroyed. The Federation ";
|
|
||||||
3500 PRINT"will be conquered":GOTO 3480
|
|
||||||
3510 PRINT"There were ";K9;" Klingon battle cruisers left at"
|
|
||||||
3520 PRINT"the end of your mission"
|
|
||||||
3530 PRINT:PRINT:IF B9=0 THEN 3670
|
|
||||||
3540 PRINT"The Federation is in need of a new starship commander"
|
|
||||||
3550 PRINT"for a similar mission -- if there is a volunteer,"
|
|
||||||
3560 INPUT"let him or her step forward and enter 'AYE' ";X$:IF X$="AYE" THEN 520
|
|
||||||
3670 END
|
|
||||||
3680 PRINT"Congratulations, Captain! the last Klingon battle cruiser"
|
|
||||||
3690 PRINT"menacing the Federation has been destroyed.":PRINT
|
|
||||||
3700 PRINT"Your efficiency rating is ";:cc1 = k7/(t-t0):PRINT 1000*cc1*cc1:GOTO 3530
|
|
||||||
3710 REM short range sensor scan & startup subroutine
|
|
||||||
3720 A$="("+chr$(174)+")":Z3=0
|
|
||||||
3721 FOR I=S1-1 TO S1+1
|
|
||||||
3722 FOR J=S2-1 TO S2+1
|
|
||||||
3730 IF INT(I+0.5)<1 OR INT(I+0.5)>8 OR INT(J+0.5)<1 OR INT(J+0.5)>8 or Z3=1 THEN 3760
|
|
||||||
3750 Z1=I:Z2=J
|
|
||||||
3751 GOSUB 4990
|
|
||||||
3760 NEXT J
|
|
||||||
3761 NEXT I
|
|
||||||
3762 IF Z3=1 THEN 3770
|
|
||||||
3763 D0=0:GOTO 3790
|
|
||||||
3770 D0=1:C$="docked":E=E0:P=P0
|
|
||||||
3780 PRINT"Shields dropped for docking purposes":S=0:GOTO 3810
|
|
||||||
3790 IF K3<=0 THEN 3800
|
|
||||||
3791 C$="*red*":GOTO 3810
|
|
||||||
3800 C$="GREEN":IF E>=E0*0.1 THEN 3810
|
|
||||||
3801 C$="YELLOW"
|
|
||||||
3810 IF D(2)>=0 THEN 3830
|
|
||||||
3820 PRINT:PRINT"*** Short Range Sensors are out ***":PRINT
|
|
||||||
3821 RETURN
|
|
||||||
3830 PRINT "-"*33
|
|
||||||
3832 FOR I=1 TO 8
|
|
||||||
3840 FOR J=(I-1)*24 TO (I-1)*24+21 STEP 3
|
|
||||||
3850 IF MID$(Q$,J+1,3)<>" " THEN 3860
|
|
||||||
3851 PRINT " . ";:GOTO 3861
|
|
||||||
3860 PRINT " ";MID$(Q$,J+1,3);
|
|
||||||
3861 NEXT J
|
|
||||||
3870 ON I GOTO 3880,3900,3910,3920,3930,3940,3950,3960
|
|
||||||
3880 PRINT" Stardate ";
|
|
||||||
3890 TT= T*10 : TT=INT(TT)*0.1:PRINT TT :GOTO 3970
|
|
||||||
3900 PRINT" Condition ";C$:GOTO 3970
|
|
||||||
3910 PRINT" Quadrant ";Q1;",";Q2:GOTO 3970
|
|
||||||
3920 PRINT" Sector ";S1;",";S2:GOTO 3970
|
|
||||||
3930 PRINT" Photon torpedoes ";INT(P):GOTO 3970
|
|
||||||
3940 PRINT" Total energy ";INT(E+S):GOTO 3970
|
|
||||||
3950 PRINT" Shields ";INT(S):GOTO 3970
|
|
||||||
3960 PRINT" Klingons remaining ";INT(K9)
|
|
||||||
3970 NEXT I
|
|
||||||
3971 PRINT "-"*33
|
|
||||||
3972 RETURN
|
|
||||||
3980 REM library computer code
|
|
||||||
3990 CM1$="GALSTATORBASDIRREG"
|
|
||||||
4000 IF D(8)>=0 THEN 4010
|
|
||||||
4001 PRINT"Computer Disabled":GOTO 1520
|
|
||||||
4010 rem KEY 1, "GAL RCD"+CHR$(13)
|
|
||||||
4020 rem KEY 2, "STATUS"+CHR$(13)
|
|
||||||
4030 rem KEY 3, "TOR DATA"+CHR$(13)
|
|
||||||
4040 rem KEY 4, "BASE NAV"+CHR$(13)
|
|
||||||
4050 rem KEY 5, "DIR/DIST"+CHR$(13)
|
|
||||||
4060 rem KEY 6, "REG MAP"+CHR$(13)
|
|
||||||
4070 rem KEY 7,CHR$(13):KEY 8,CHR$(13):KEY 9,CHR$(13):KEY 10,CHR$(13)
|
|
||||||
4071 gosub 4130
|
|
||||||
4080 INPUT"Computer active and awaiting command ";CM$:H8=1
|
|
||||||
4090 FOR K1= 1 TO 6
|
|
||||||
4100 IF MID$(CM$,1,3)<>MID$(CM1$,3*K1-2,3) THEN 4120
|
|
||||||
4110 ON K1 GOTO 4250,4400,4490,4750,4550,4210
|
|
||||||
4120 NEXT K1
|
|
||||||
4121 gosub 4130
|
|
||||||
4122 goto 4080
|
|
||||||
4130 PRINT"Functions available from library-computer:"
|
|
||||||
4140 PRINT" GAL = Cumulative galactic record"
|
|
||||||
4150 PRINT" STA = Status report"
|
|
||||||
4160 PRINT" TOR = Photon torpedo data"
|
|
||||||
4170 PRINT" BAS = Starbase nav data"
|
|
||||||
4180 PRINT" DIR = Direction/distance calculator"
|
|
||||||
4190 PRINT" REG = Galaxy 'region name' map":PRINT
|
|
||||||
4191 return
|
|
||||||
4200 REM setup to change cum gal record to galaxy map
|
|
||||||
4210 H8=0:G5=1:PRINT" the galaxy":GOTO 4290
|
|
||||||
4250 PRINT:PRINT" ";
|
|
||||||
4270 PRINT "Computer record of galaxy for quadrant ";Q1;",";Q2
|
|
||||||
4280 PRINT
|
|
||||||
4290 PRINT" 1 2 3 4 5 6 7 8"
|
|
||||||
4300 O1$=" ----- ----- ----- ----- ----- ----- ----- -----"
|
|
||||||
4310 PRINT O1$
|
|
||||||
4311 FOR I=1 TO 8
|
|
||||||
4312 PRINT I;" ";:IF H8=0 THEN 4350
|
|
||||||
4320 FOR J=1 TO 8
|
|
||||||
4321 PRINT" ";:IF Z(I,J)<>0 THEN 4330
|
|
||||||
4322 PRINT"***";:GOTO 4340
|
|
||||||
4330 ZLEN = len(str$(z(i,j)+1000)
|
|
||||||
4331 PRINT MID$(STR$(Z(I,J)+1000),zlen-2,3);
|
|
||||||
4340 NEXT J
|
|
||||||
4341 GOTO 4370
|
|
||||||
4350 Z4=I:Z5=1
|
|
||||||
4351 GOSUB 5040
|
|
||||||
4352 J0=INT(15-0.5*LEN(G2$)):PRINT TAB(J0);G2$;
|
|
||||||
4360 Z5=5
|
|
||||||
4361 GOSUB 5040
|
|
||||||
4362 J0=INT(40-0.5*LEN(G2$)):PRINT TAB(J0);G2$;
|
|
||||||
4370 PRINT:PRINT O1$
|
|
||||||
4371 NEXT I
|
|
||||||
4372 PRINT
|
|
||||||
4373 rem 'POKE 1229,0 POKE 1237,1
|
|
||||||
4380 GOTO 1520
|
|
||||||
4390 REM status report
|
|
||||||
4400 PRINT" Status Report":X$="":IF K9<=1 THEN 4410
|
|
||||||
4402 X$="s"
|
|
||||||
4410 PRINT"Klingon";X$;" left: ";K9
|
|
||||||
4420 PRINT"Mission must be completed in ";0.1*INT((T0+T9-T)*10);" stardates"
|
|
||||||
4430 X$="s":IF B9>=2 THEN 4440
|
|
||||||
4431 X$="":IF B9<1 THEN 4460
|
|
||||||
4440 PRINT"The federation is maintaining ";B9;" starbase";X$;" in the galaxy"
|
|
||||||
4450 GOTO 3180
|
|
||||||
4460 PRINT"Your stupidity has left you on your own in"
|
|
||||||
4470 PRINT" the galaxy -- you have no starbases left!":GOTO 3180
|
|
||||||
4480 REM torpedo, base nav, d/d calculator
|
|
||||||
4490 IF K3<=0 THEN 2550
|
|
||||||
4500 X$="":IF K3<=1 THEN 4510
|
|
||||||
4501 X$="s"
|
|
||||||
4510 PRINT"From ENTERPRISE to Klingon battle cruiser";X$
|
|
||||||
4520 H8=0:FOR I=1 TO 3
|
|
||||||
4521 IF K(I,3)<=0 THEN 4740
|
|
||||||
4530 W1=K(I,1):X=K(I,2)
|
|
||||||
4540 C1=S1:A=S2:GOTO 4590
|
|
||||||
4550 PRINT"Direction/Distance Calculator:"
|
|
||||||
4560 PRINT"You are at quadrant ";Q1;",";Q2;" sector ";S1;",";S2
|
|
||||||
4570 PRINT"Please enter ":INPUT" initial coordinates (x,y) ";C1,A
|
|
||||||
4580 INPUT" Final coordinates (x,y) ";W1,X
|
|
||||||
4590 X=X-A:A=C1-W1:aa=abs(a):ax=abs(x):IF X<0 THEN 4670
|
|
||||||
4600 IF A<0 THEN 4690
|
|
||||||
4610 IF X>0 THEN 4630
|
|
||||||
4620 IF A<>0 THEN 4630
|
|
||||||
4621 C1=5:GOTO 4640
|
|
||||||
4630 C1=1
|
|
||||||
4640 IF AA<=AX THEN 4660
|
|
||||||
4650 PRINT"Direction1 = ";:cc1=(AA-AX+AA)/AA:PRINT c1+cc1:GOTO 4730
|
|
||||||
4660 PRINT"Direction2 = ";:cc1=C1+(AA/AX):PRINT cc1:GOTO 4730
|
|
||||||
4670 IF A<=0 THEN 4680
|
|
||||||
4671 C1=3:GOTO 4700
|
|
||||||
4680 IF X=0 THEN 4690
|
|
||||||
4681 C1=5:GOTO 4640
|
|
||||||
4690 C1=7
|
|
||||||
4700 IF AA>=AX THEN 4720
|
|
||||||
4710 PRINT"Direction3 = ";:cc1=(AX-AA+AX)/AX:PRINT c1+cc1:GOTO 4730
|
|
||||||
4720 PRINT"Direction4 = ";:CC1=C1+(AX/AA):PRINT CC1
|
|
||||||
4730 PRINT"Distance = ";:cc1=SQR(x*X+A*A):PRINT cc1:IF H8=1 THEN 1520
|
|
||||||
4740 NEXT I
|
|
||||||
4741 GOTO 1520
|
|
||||||
4750 IF B3=0 THEN 4770
|
|
||||||
4752 PRINT"From ENTERPRISE to Starbase:":W1=B4:X=B5
|
|
||||||
4760 GOTO 4540
|
|
||||||
4770 PRINT"Mr. Spock reports, 'Sensors show no starbases in this";
|
|
||||||
4780 PRINT"quadrant.'":GOTO 1520
|
|
||||||
4790 REM find empty place in quadrant (for things)
|
|
||||||
4800 R1=INT(RND(1)*7.98+1.01):R2=INT(RND(1)*7.98+1.01):A$=" ":Z1=R1:Z2=R2
|
|
||||||
4801 GOSUB 4990
|
|
||||||
4802 IF Z3=0 THEN 4800
|
|
||||||
4810 RETURN
|
|
||||||
4820 REM insert in string array for quadrant
|
|
||||||
4830 S8=INT(Z2-0.5)*3+INT(Z1-0.5)*24+1
|
|
||||||
4840 IF LEN(A$)=3 THEN 4850
|
|
||||||
4841 PRINT"ERROR":STOP
|
|
||||||
4850 IF S8<>1 THEN 4860
|
|
||||||
4851 Q$=A$+MID$(Q$,4,189):RETURN
|
|
||||||
4860 IF S8<>190 THEN 4870
|
|
||||||
4861 Q$=MID$(Q$,1,189)+A$:RETURN
|
|
||||||
4870 Q$=MID$(Q$,1,S8-1)+A$+MID$(Q$,s8+3,192-s8-2):RETURN
|
|
||||||
4880 REM prints device name
|
|
||||||
4890 ON R1 GOTO 4900,4910,4920,4930,4940,4950,4960,4970
|
|
||||||
4900 G2$="Warp Engines":RETURN
|
|
||||||
4910 G2$="Short Range Sensors":RETURN
|
|
||||||
4920 G2$="Long Range Sensors":RETURN
|
|
||||||
4930 G2$="Phaser Control":RETURN
|
|
||||||
4940 G2$="Photon Tubes":RETURN
|
|
||||||
4950 G2$="Damage Control":RETURN
|
|
||||||
4960 G2$="Shield Control":RETURN
|
|
||||||
4970 G2$="Library-Computer":RETURN
|
|
||||||
4980 REM string comparison in quadrant array
|
|
||||||
4990 Z1=INT(Z1+0.5):Z2=INT(Z2+0.5):S8=(Z2-1)*3+(Z1-1)*24:Z3=0
|
|
||||||
5000 IF MID$(Q$,S8+1,3)=A$ THEN 5010
|
|
||||||
5001 RETURN
|
|
||||||
5010 Z3=1:RETURN
|
|
||||||
5020 REM quadrant name in g2$ from z4,z5 (=q1,q2)
|
|
||||||
5030 REM call with g5=1 to get region name only
|
|
||||||
5040 IF Z5<=4 THEN 5140
|
|
||||||
5041 ON Z4 GOTO 5060,5070,5080,5090,5100,5110,5120,5130
|
|
||||||
5050 GOTO 5140
|
|
||||||
5060 G2$="Antares":GOTO 5230
|
|
||||||
5070 G2$="Rigel":GOTO 5230
|
|
||||||
5080 G2$="Procyon":GOTO 5230
|
|
||||||
5090 G2$="Vega":GOTO 5230
|
|
||||||
5100 G2$="Canopus":GOTO 5230
|
|
||||||
5110 G2$="Altair":GOTO 5230
|
|
||||||
5120 G2$="Sagittarius":GOTO 5230
|
|
||||||
5130 G2$="Pollux":GOTO 5230
|
|
||||||
5140 ON Z4 GOTO 5150,5160,5170,5180,5180,5200,5210,5220
|
|
||||||
5150 G2$="Sirius":GOTO 5230
|
|
||||||
5160 G2$="Deneb":GOTO 5230
|
|
||||||
5170 G2$="Capella":GOTO 5230
|
|
||||||
5180 G2$="Betelgeuse":GOTO 5230
|
|
||||||
5190 G2$="Aldebaran":GOTO 5230
|
|
||||||
5200 G2$="Regulus":GOTO 5230
|
|
||||||
5210 G2$="Arcturus":GOTO 5230
|
|
||||||
5220 G2$="Spica"
|
|
||||||
5230 IF G5=1 THEN 5240
|
|
||||||
5231 ON Z5 GOTO 5250,5260,5270,5280,5250,5260,5270,5280
|
|
||||||
5240 RETURN
|
|
||||||
5250 G2$=G2$+" i":RETURN
|
|
||||||
5260 G2$=G2$+" ii":RETURN
|
|
||||||
5270 G2$=G2$+" iii":RETURN
|
|
||||||
5280 G2$=G2$+" iv":RETURN
|
|
||||||
5290 rem red alert sound
|
|
||||||
5291 return
|
|
||||||
5300 FOR J= 1 TO 4
|
|
||||||
5310 FOR K=1000 TO 2000 STEP 20
|
|
||||||
5320 rem SOUND K,0.01*18.2
|
|
||||||
5330 NEXT K
|
|
||||||
5340 NEXT J
|
|
||||||
5350 RETURN
|
|
||||||
5360 rem torpedo sound
|
|
||||||
5361 return
|
|
||||||
5370 FOR J = 1500 TO 100 STEP -20
|
|
||||||
5380 rem SOUND J,0.01*18.2
|
|
||||||
5390 rem SOUND 3600-J,.01*18.2
|
|
||||||
5400 NEXT J
|
|
||||||
5410 RETURN
|
|
||||||
5420 rem phaser sound
|
|
||||||
5421 return
|
|
||||||
5430 FOR J= 1 TO 40
|
|
||||||
5440 rem SOUND 800,.01*18.2
|
|
||||||
5450 rem SOUND 2500,.008*18.2
|
|
||||||
5460 NEXT J
|
|
||||||
5470 RETURN
|
|
||||||
5480 rem alarm sound
|
|
||||||
5481 return
|
|
||||||
5490 FOR SI = 1 TO 3
|
|
||||||
5500 FOR J= 800 TO 1500 STEP 20
|
|
||||||
5510 rem SOUND J,.01 *18.2
|
|
||||||
5520 NEXT J
|
|
||||||
5530 FOR K = 1500 TO 800 STEP -20
|
|
||||||
5540 rem SOUND K, .01 *18.2
|
|
||||||
5550 NEXT K
|
|
||||||
5560 NEXT SI
|
|
||||||
5570 RETURN
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,83 +0,0 @@
|
||||||
5 PRINT TAB(33);"BAGELS"
|
|
||||||
10 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY":PRINT:PRINT
|
|
||||||
15 REM *** BAGLES NUMBER GUESSING GAME
|
|
||||||
20 REM *** ORIGINAL SOURCE UNKNOWN BUT SUSPECTED TO BE
|
|
||||||
25 REM *** LAWRENCE HALL OF SCIENCE UC BERKELY
|
|
||||||
30 DIM A1(6),A(3),B(3)
|
|
||||||
40 Y=0:T=255
|
|
||||||
50 PRINT:PRINT:PRINT
|
|
||||||
70 INPUT "WOULD YOU LIKE THE RULES (YES OR NO)";A$
|
|
||||||
90 IF LEFT$(A$,1)="N" THEN 150
|
|
||||||
100 PRINT:PRINT "I AM THINKING OF A THREE-DIGIT NUMBER. TRY TO GUESS"
|
|
||||||
110 PRINT "MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:"
|
|
||||||
120 PRINT " PICO - ONE DIGIT CORRECT BUT IN THE WRONG POSITION"
|
|
||||||
130 PRINT " FERMI - ONE DIGIT CORRECT AND IN THE RIGHT POSITION"
|
|
||||||
140 PRINT " BAGELS - NO DIGITS CORRECT"
|
|
||||||
150 FOR I=1 TO 3
|
|
||||||
160 A(I)=INT(10*RND(1))
|
|
||||||
165 IF I-1=0 THEN 200
|
|
||||||
170 FOR J=1 TO I-1
|
|
||||||
180 IF A(I)=A(J) THEN 160
|
|
||||||
190 NEXT J
|
|
||||||
200 NEXT I
|
|
||||||
210 PRINT:PRINT "O.K. I HAVE A NUMBER IN MIND."
|
|
||||||
220 FOR I=1 TO 20
|
|
||||||
230 PRINT "GUESS #";I
|
|
||||||
240 INPUT A$
|
|
||||||
245 IF LEN(A$)<>3 THEN 630
|
|
||||||
250 FOR Z=1 TO 3
|
|
||||||
251 A1(Z)=ASC(MID$(A$,Z,1))
|
|
||||||
252 NEXT Z
|
|
||||||
260 FOR J=1 TO 3
|
|
||||||
270 IF A1(J)<48 THEN 300
|
|
||||||
280 IF A1(J)>57 THEN 300
|
|
||||||
285 B(J)=A1(J)-48
|
|
||||||
290 NEXT J
|
|
||||||
295 GOTO 320
|
|
||||||
300 PRINT "WHAT?"
|
|
||||||
310 GOTO 230
|
|
||||||
320 IF B(1)=B(2) THEN 650
|
|
||||||
330 IF B(2)=B(3) THEN 650
|
|
||||||
340 IF B(3)=B(1) THEN 650
|
|
||||||
350 C=0:D=0
|
|
||||||
360 FOR J=1 TO 2
|
|
||||||
370 IF A(J)<>B(J+1) THEN 390
|
|
||||||
380 C=C+1
|
|
||||||
390 IF A(J+1)<>B(J) THEN 410
|
|
||||||
400 C=C+1
|
|
||||||
410 NEXT J
|
|
||||||
420 IF A(1)<>B(3) THEN 440
|
|
||||||
430 C=C+1
|
|
||||||
440 IF A(3)<>B(1) THEN 460
|
|
||||||
450 C=C+1
|
|
||||||
460 FOR J=1 TO 3
|
|
||||||
470 IF A(J)<>B(J) THEN 490
|
|
||||||
480 D=D+1
|
|
||||||
490 NEXT J
|
|
||||||
500 IF D=3 THEN 680
|
|
||||||
505 IF C=0 THEN 545
|
|
||||||
520 FOR J=1 TO C
|
|
||||||
530 PRINT "PICO ";
|
|
||||||
540 NEXT J
|
|
||||||
545 IF D=0 THEN 580
|
|
||||||
550 FOR J=1 TO D
|
|
||||||
560 PRINT "FERMI ";
|
|
||||||
570 NEXT J
|
|
||||||
580 IF C+D<>0 THEN 600
|
|
||||||
590 PRINT "BAGELS";
|
|
||||||
600 PRINT
|
|
||||||
605 NEXT I
|
|
||||||
610 PRINT "OH WELL."
|
|
||||||
615 PRINT "THAT'S TWNETY GUESSES. MY NUMBER WAS";100*A(1)+10*A(2)+A(3)
|
|
||||||
620 GOTO 700
|
|
||||||
630 PRINT "TRY GUESSING A THREE-DIGIT NUMBER.":GOTO 230
|
|
||||||
650 PRINT "OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND"
|
|
||||||
660 PRINT "HAS NO TWO DIGITS THE SAME.":GOTO 230
|
|
||||||
680 PRINT "YOU GOT IT!!!":PRINT
|
|
||||||
690 Y=Y+1
|
|
||||||
700 INPUT "PLAY AGAIN (YES OR NO)";A$
|
|
||||||
720 IF LEFT$(A$,1)="YES" THEN 150
|
|
||||||
730 IF Y=0 THEN 750
|
|
||||||
740 PRINT:PRINT "A";Y;"POINT BAGELS BUFF!!"
|
|
||||||
750 PRINT "HOPE YOU HAD FUN. BYE."
|
|
||||||
999 END
|
|
||||||
|
|
@ -1,234 +0,0 @@
|
||||||
5 PRINT TAB ( 16 ) ; "**************************"
|
|
||||||
10 PRINT TAB ( 26 ) ; "ELIZA"
|
|
||||||
20 PRINT TAB ( 20 ) ; "CREATIVE COMPUTING"
|
|
||||||
30 PRINT TAB ( 18 ) ; "MORRISTOWN, NEW JERSEY" : PRINT
|
|
||||||
40 PRINT TAB ( 19 ) ; "ADAPTED FOR IBM PC BY"
|
|
||||||
50 PRINT TAB ( 12 ) ; "PATRICIA DANIELSON AND PAUL HASHFIELD"
|
|
||||||
53 PRINT : PRINT TAB ( 6 ) ; "PLEASE DON'T USE COMMAS OR PERIODS IN YOUR INPUTS" : PRINT
|
|
||||||
55 PRINT TAB ( 16 ) ; "*************************"
|
|
||||||
60 PRINT : PRINT : PRINT
|
|
||||||
80 REM*****INITIALIZATION**********
|
|
||||||
100 DIM S ( 36 ) , R ( 36 ) , N ( 36 )
|
|
||||||
105 DIM KEYWORD$ ( 36 ) , WORDIN$ ( 7 ) , WORDOUT$ ( 7 ) , REPLIES$ ( 112 )
|
|
||||||
107 REM NEED TO PRE-DECLARE BEFORE USE
|
|
||||||
108 P$ = "NULL"
|
|
||||||
110 N1 = 36 : N2 = 14 : N3 = 112
|
|
||||||
112 FOR X = 1 TO N1
|
|
||||||
113 READ TEMP$: KEYWORD$ ( X ) = TEMP$
|
|
||||||
114 NEXT X
|
|
||||||
115 FOR X = 1 TO N2 / 2
|
|
||||||
116 READ TEMP$: WORDIN$ ( X ) = TEMP$ : READ TEMP$: WORDOUT$ ( X ) = TEMP$
|
|
||||||
117 NEXT X
|
|
||||||
118 FOR X = 1 TO N3
|
|
||||||
119 READ TEMP$: REPLIES$ ( X ) = TEMP$
|
|
||||||
120 NEXT X
|
|
||||||
130 FOR X = 1 TO N1
|
|
||||||
140 READ TEMP: S ( X ) = TEMP: READ TEMP: L = TEMP
|
|
||||||
142 R ( X ) = S ( X ) : N ( X ) = S ( X ) + L - 1
|
|
||||||
150 NEXT X
|
|
||||||
160 PRINT "HI! I'M ELIZA. WHAT'S YOUR PROBLEM?"
|
|
||||||
170 REM ***********************************
|
|
||||||
180 REM *******USER INPUT SECTION**********
|
|
||||||
190 REM ***********************************
|
|
||||||
200 INPUT I$
|
|
||||||
201 I$ = " " + I$ + " "
|
|
||||||
210 REM GET RID OF APOSTROPHES
|
|
||||||
220 FOR L = 1 TO LEN ( I$ )
|
|
||||||
230 REM IF MID$(I$,L,1)="'"THEN I$=LEFT$(I$,L-1)+RIGHT$(I$,LEN(I$)-L):GOTO 230
|
|
||||||
240 IF L + 4 > LEN ( I$ ) THEN 250
|
|
||||||
241 IF MID$ ( I$ , L , 4 ) <> "SHUT" THEN 250
|
|
||||||
242 PRINT "O.K. IF YOU FEEL THAT WAY I'LL SHUT UP...."
|
|
||||||
243 END
|
|
||||||
250 NEXT L
|
|
||||||
255 IF I$ = P$ THEN 256 ELSE 260
|
|
||||||
256 PRINT "PLEASE DON'T REPEAT YOURSELF!": GOTO 170
|
|
||||||
260 REM ***********************************
|
|
||||||
270 REM ********FIND KEYWORD IN I$*********
|
|
||||||
280 REM ***********************************
|
|
||||||
300 FOR K = 1 TO N1
|
|
||||||
320 FOR L = 1 TO LEN ( I$ ) - LEN ( KEYWORD$ ( K ) ) + 1
|
|
||||||
340 IF MID$ ( I$ , L , LEN ( KEYWORD$ ( K ) ) ) <> KEYWORD$ ( K ) THEN 350
|
|
||||||
341 IF K <> 13 THEN 349
|
|
||||||
342 IF MID$ ( I$ , L , LEN ( KEYWORD$ ( 29 ) ) ) = KEYWORD$ ( 29 ) THEN 343 ELSE 349
|
|
||||||
343 K = 29
|
|
||||||
349 F$ = KEYWORD$ ( K ) : GOTO 390
|
|
||||||
350 NEXT L
|
|
||||||
360 NEXT K
|
|
||||||
370 K = 36 : GOTO 570 : REM WE DIDN'T FIND ANY KEYWORDS
|
|
||||||
380 REM ******************************************
|
|
||||||
390 REM **TAKE PART OF STRING AND CONJUGATE IT****
|
|
||||||
400 REM **USING THE LIST OF STRINGS TO BE SWAPPED*
|
|
||||||
410 REM ******************************************
|
|
||||||
430 C$ = " " + RIGHT$ ( I$ , LEN ( I$ ) - LEN ( F$ ) - L + 1 ) + " "
|
|
||||||
440 FOR X = 1 TO N2 / 2
|
|
||||||
460 FOR L = 1 TO LEN ( C$ )
|
|
||||||
470 IF L + LEN ( WORDIN$ ( X ) ) > LEN ( C$ ) THEN 510
|
|
||||||
480 IF MID$ ( C$ , L , LEN ( WORDIN$ ( X ) ) ) <> WORDIN$ ( X ) THEN 510
|
|
||||||
490 C$ = LEFT$ ( C$ , L - 1 ) + WORDOUT$ ( X ) + RIGHT$ ( C$ , LEN ( C$ ) - L - LEN ( WORDIN$ ( X ) ) + 1 )
|
|
||||||
495 L = L + LEN ( WORDOUT$ ( X ) )
|
|
||||||
500 GOTO 540
|
|
||||||
510 IF L + LEN ( WORDOUT$ ( X ) ) > LEN ( C$ ) THEN 540
|
|
||||||
520 IF MID$ ( C$ , L , LEN ( WORDOUT$ ( X ) ) ) <> WORDOUT$ ( X ) THEN 540
|
|
||||||
530 C$ = LEFT$ ( C$ , L - 1 ) + WORDIN$ ( X ) + RIGHT$ ( C$ , LEN ( C$ ) - L - LEN ( WORDOUT$ ( X ) ) + 1 )
|
|
||||||
535 L = L + LEN ( WORDIN$ ( X ) )
|
|
||||||
540 NEXT L
|
|
||||||
550 NEXT X
|
|
||||||
551 IF MID$ ( C$ , 2 , 1 ) = " " THEN 552 ELSE 555
|
|
||||||
552 C$ = RIGHT$ ( C$ , LEN ( C$ ) - 1 ) : REM ONLY 1 SPACE
|
|
||||||
555 FOR L = 1 TO LEN ( C$ )
|
|
||||||
556 IF MID$ ( C$ , L , 1 ) = "!" THEN 557 ELSE 558
|
|
||||||
557 C$ = LEFT$ ( C$ , L - 1 ) + RIGHT$ ( C$ , LEN ( C$ ) - L ) : GOTO 556
|
|
||||||
558 NEXT L
|
|
||||||
560 REM **********************************************
|
|
||||||
570 REM **NOW USING THE KEYWORD NUMBER (K) GET REPLY**
|
|
||||||
580 REM **********************************************
|
|
||||||
600 F$ = REPLIES$ ( R ( K ) )
|
|
||||||
610 R ( K ) = R ( K ) + 1
|
|
||||||
615 IF R ( K ) > N ( K ) THEN 617 ELSE 620
|
|
||||||
617 R ( K ) = S ( K )
|
|
||||||
620 IF RIGHT$ ( F$ , 1 ) <> "*" THEN 621 ELSE 625
|
|
||||||
621 PRINT F$ : P$ = I$ : GOTO 170
|
|
||||||
625 IF C$ <> " " THEN 630
|
|
||||||
626 PRINT "YOU WILL HAVE TO ELABORATE MORE FOR ME TO HELP YOU"
|
|
||||||
627 GOTO 170
|
|
||||||
630 PRINT LEFT$ ( F$ , LEN ( F$ ) - 1 ) ; C$
|
|
||||||
640 P$ = I$ : GOTO 170
|
|
||||||
1000 REM *******************************
|
|
||||||
1010 REM *****PROGRAM DATA FOLLOWS******
|
|
||||||
1020 REM *******************************
|
|
||||||
1030 REM *********KEYWORDS**************
|
|
||||||
1049 REM *******************************
|
|
||||||
1050 DATA "CAN YOU " , "CAN I " , "YOU ARE " , "YOU'RE " , "I DON'T " , "I FEEL "
|
|
||||||
1060 DATA "WHY DON'T YOU " , "WHY CAN'T I " , "ARE YOU " , "I CAN'T " , "I AM " , "I'M "
|
|
||||||
1070 DATA "YOU " , "I WANT " , "WHAT " , "HOW " , "WHO " , "WHERE " , "WHEN " , "WHY "
|
|
||||||
1080 DATA "NAME " , "CAUSE " , "SORRY " , "DREAM " , "HELLO " , "HI " , "MAYBE "
|
|
||||||
1090 DATA "NO" , "YOUR " , "ALWAYS " , "THINK " , "ALIKE " , "YES " , "FRIEND "
|
|
||||||
1100 DATA "COMPUTER" , "NOKEYFOUND"
|
|
||||||
1200 REM *********************************
|
|
||||||
1210 REM ***STRING DATA FOR CONJUGATIONS**
|
|
||||||
1220 REM *********************************
|
|
||||||
1230 DATA " ARE " , " AM " , " WERE " , " WAS " , " YOU " , " I " , " YOUR" , " MY "
|
|
||||||
1235 DATA " I'VE " , " YOU'VE " , " I'M " , " YOU'RE "
|
|
||||||
1240 DATA " ME " , " YOU "
|
|
||||||
1300 REM ******************************
|
|
||||||
1310 REM *********REPLIES**************
|
|
||||||
1320 REM ******************************
|
|
||||||
1330 DATA "DON'T YOU BELIEVE THAT I CAN*"
|
|
||||||
1340 DATA "PERHAPS YOU WOULD LIKE TO BE LIKE ME*"
|
|
||||||
1350 DATA "YOU WANT ME TO BE ABLE TO*"
|
|
||||||
1360 DATA "PERHAPS YOU DON'T WANT TO*"
|
|
||||||
1365 DATA "DO YOU WANT TO BE ABLE TO*"
|
|
||||||
1370 DATA "WHAT MAKES YOU THINK I AM*"
|
|
||||||
1380 DATA "DOES IT PLEASE YOU TO BELIEVE I AM*"
|
|
||||||
1390 DATA "PERHAPS YOU WOULD LIKE TO BE*"
|
|
||||||
1400 DATA "DO YOU SOMETIMES WISH YOU WERE*"
|
|
||||||
1410 DATA "DON'T YOU REALLY*"
|
|
||||||
1420 DATA "WHY DON'T YOU*"
|
|
||||||
1430 DATA "DO YOU WISH TO BE ABLE TO*"
|
|
||||||
1440 DATA "DOES THAT TROUBLE YOU*"
|
|
||||||
1450 DATA "DO YOU OFTEN FEEL*"
|
|
||||||
1460 DATA "DO YOU OFTEN FEEL*"
|
|
||||||
1470 DATA "DO YOU ENJOY FEELING*"
|
|
||||||
1480 DATA "DO YOU REALLY BELIEVE I DON'T*"
|
|
||||||
1490 DATA "PERHAPS IN GOOD TIME I WILL*"
|
|
||||||
1500 DATA "DO YOU WANT ME TO*"
|
|
||||||
1510 DATA "DO YOU THINK YOU SHOULD BE ABLE TO*"
|
|
||||||
1520 DATA "WHY CAN'T YOU*"
|
|
||||||
1530 DATA "WHY ARE YOU INTERESTED IN WHETHER OR NOT I AM*"
|
|
||||||
1540 DATA "WOULD YOU PREFER IF I WERE NOT*"
|
|
||||||
1550 DATA "PERHAPS IN YOUR FANTASIES I AM*"
|
|
||||||
1560 DATA "HOW DO YOU KNOW YOU CAN'T*"
|
|
||||||
1570 DATA "HAVE YOU TRIED?"
|
|
||||||
1580 DATA "PERHAPS YOU CAN NOW*"
|
|
||||||
1590 DATA "DID YOU COME TO ME BECAUSE YOU ARE*"
|
|
||||||
1600 DATA "HOW LONG HAVE YOU BEEN*"
|
|
||||||
1610 DATA "DO YOU BELIEVE IT IS NORMAL TO BE*"
|
|
||||||
1620 DATA "DO YOU ENJOY BEING*"
|
|
||||||
1630 DATA "WE WERE DISCUSSING YOU--NOT ME."
|
|
||||||
1640 DATA "OH, I*"
|
|
||||||
1650 DATA "YOU'RE NOT REALLY TALKING ABOUT ME, ARE YOU?"
|
|
||||||
1660 DATA "WHAT WOULD IT MEAN TO YOU IF YOU GOT*"
|
|
||||||
1670 DATA "WHY DO YOU WANT*"
|
|
||||||
1680 DATA "SUPPOSE YOU SOON GOT*"
|
|
||||||
1690 DATA "WHAT IF YOU NEVER GOT*"
|
|
||||||
1700 DATA "I SOMETIMES ALSO WANT*"
|
|
||||||
1710 DATA "WHY DO YOU ASK?"
|
|
||||||
1720 DATA "DOES THAT QUESTION INTEREST YOU?"
|
|
||||||
1730 DATA "WHAT ANSWER WOULD PLEASE YOU THE MOST?"
|
|
||||||
1740 DATA "WHAT DO YOU THINK?"
|
|
||||||
1750 DATA "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?"
|
|
||||||
1760 DATA "WHAT IS IT THAT YOU REALLY WANT TO KNOW?"
|
|
||||||
1770 DATA "HAVE YOU ASKED ANYONE ELSE?"
|
|
||||||
1780 DATA "HAVE YOU ASKED SUCH QUESTIONS BEFORE?"
|
|
||||||
1790 DATA "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"
|
|
||||||
1800 DATA "NAMES DON'T INTEREST ME."
|
|
||||||
1810 DATA "I DON'T CARE ABOUT NAMES --PLEASE GO ON."
|
|
||||||
1820 DATA "IS THAT THE REAL REASON?"
|
|
||||||
1830 DATA "DON'T ANY OTHER REASONS COME TO MIND?"
|
|
||||||
1840 DATA "DOES THAT REASON EXPLAIN ANYTHING ELSE?"
|
|
||||||
1850 DATA "WHAT OTHER REASONS MIGHT THERE BE?"
|
|
||||||
1860 DATA "PLEASE DON'T APOLOGIZE!"
|
|
||||||
1870 DATA "APOLOGIES ARE NOT NECESSARY."
|
|
||||||
1880 DATA "WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE?"
|
|
||||||
1890 DATA "DON'T BE SO DEFENSIVE!"
|
|
||||||
1900 DATA "WHAT DOES THAT DREAM SUGGEST TO YOU?"
|
|
||||||
1910 DATA "DO YOU DREAM OFTEN?"
|
|
||||||
1920 DATA "WHAT PERSONS APPEAR IN YOUR DREAMS?"
|
|
||||||
1930 DATA "ARE YOU DISTURBED BY YOUR DREAMS?"
|
|
||||||
1940 DATA "HOW DO YOU DO ...PLEASE STATE YOUR PROBLEM."
|
|
||||||
1950 DATA "YOU DON'T SEEM QUITE CERTAIN."
|
|
||||||
1960 DATA "WHY THE UNCERTAIN TONE?"
|
|
||||||
1970 DATA "CAN'T YOU BE MORE POSITIVE?"
|
|
||||||
1980 DATA "YOU AREN'T SURE?"
|
|
||||||
1990 DATA "DON'T YOU KNOW?"
|
|
||||||
2000 DATA "ARE YOU SAYING NO JUST TO BE NEGATIVE?"
|
|
||||||
2010 DATA "YOU ARE BEING A BIT NEGATIVE."
|
|
||||||
2020 DATA "WHY NOT?"
|
|
||||||
2030 DATA "ARE YOU SURE?"
|
|
||||||
2040 DATA "WHY NO?"
|
|
||||||
2050 DATA "WHY ARE YOU CONCERNED ABOUT MY*"
|
|
||||||
2060 DATA "WHAT ABOUT YOUR OWN*"
|
|
||||||
2070 DATA "CAN YOU THINK OF A SPECIFIC EXAMPLE?"
|
|
||||||
2080 DATA "WHEN?"
|
|
||||||
2090 DATA "WHAT ARE YOU THINKING OF?"
|
|
||||||
2100 DATA "REALLY, ALWAYS?"
|
|
||||||
2110 DATA "DO YOU REALLY THINK SO?"
|
|
||||||
2120 DATA "BUT YOU ARE NOT SURE YOU*"
|
|
||||||
2130 DATA "DO YOU DOUBT YOU*"
|
|
||||||
2140 DATA "IN WHAT WAY?"
|
|
||||||
2150 DATA "WHAT RESEMBLANCE DO YOU SEE?"
|
|
||||||
2160 DATA "WHAT DOES THE SIMILARITY SUGGEST TO YOU?"
|
|
||||||
2170 DATA "WHAT OTHER CONNECTIONS DO YOU SEE?"
|
|
||||||
2180 DATA "COULD THERE REALLY BE SOME CONNECTION?"
|
|
||||||
2190 DATA "HOW?"
|
|
||||||
2200 DATA "YOU SEEM QUITE POSITIVE."
|
|
||||||
2210 DATA "ARE YOU SURE?"
|
|
||||||
2220 DATA "I SEE."
|
|
||||||
2230 DATA "I UNDERSTAND."
|
|
||||||
2240 DATA "WHY DO YOU BRING UP THE TOPIC OF FRIENDS?"
|
|
||||||
2250 DATA "DO YOUR FRIENDS WORRY YOU?"
|
|
||||||
2260 DATA "DO YOUR FRIENDS PICK ON YOU?"
|
|
||||||
2270 DATA "ARE YOU SURE YOU HAVE ANY FRIENDS?"
|
|
||||||
2280 DATA "DO YOU IMPOSE ON YOUR FRIENDS?"
|
|
||||||
2290 DATA "PERHAPS YOUR LOVE FOR FRIENDS WORRIES YOU."
|
|
||||||
2300 DATA "DO COMPUTERS WORRY YOU?"
|
|
||||||
2310 DATA "ARE YOU TALKING ABOUT ME IN PARTICULAR?"
|
|
||||||
2320 DATA "ARE YOU FRIGHTENED BY MACHINES?"
|
|
||||||
2330 DATA "WHY DO YOU MENTION COMPUTERS?"
|
|
||||||
2340 DATA "WHAT DO YOU THINK MACHINES HAVE TO DO WITH YOUR PROBLEM?"
|
|
||||||
2350 DATA "DON'T YOU THINK COMPUTERS CAN HELP PEOPLE?"
|
|
||||||
2360 DATA "WHAT IS IT ABOUT MACHINES THAT WORRIES YOU?"
|
|
||||||
2370 DATA "SAY, DO YOU HAVE ANY PSYCHOLOGICAL PROBLEMS?"
|
|
||||||
2380 DATA "WHAT DOES THAT SUGGEST TO YOU?"
|
|
||||||
2390 DATA "I SEE."
|
|
||||||
2400 DATA "I'M NOT SURE I UNDERSTAND YOU FULLY."
|
|
||||||
2410 DATA "COME COME ELUCIDATE YOUR THOUGHTS."
|
|
||||||
2420 DATA "CAN YOU ELABORATE ON THAT?"
|
|
||||||
2430 DATA "THAT IS QUITE INTERESTING."
|
|
||||||
2500 REM *************************
|
|
||||||
2510 REM *****DATA FOR FINDING RIGHT REPLIES
|
|
||||||
2520 REM *************************
|
|
||||||
2530 DATA 1 , 3 , 4 , 2 , 6 , 4 , 6 , 4 , 10 , 4 , 14 , 3 , 17 , 3 , 20 , 2 , 22 , 3 , 25 , 3
|
|
||||||
2540 DATA 28 , 4 , 28 , 4 , 32 , 3 , 35 , 5 , 40 , 9 , 40 , 9 , 40 , 9 , 40 , 9 , 40 , 9 , 40 , 9
|
|
||||||
2550 DATA 49 , 2 , 51 , 4 , 55 , 4 , 59 , 4 , 63 , 1 , 63 , 1 , 64 , 5 , 69 , 5 , 74 , 2 , 76 , 4
|
|
||||||
2560 DATA 80 , 3 , 83 , 7 , 90 , 3 , 93 , 6 , 99 , 7 , 106 , 6
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
10 REM A SHORT PROGRAM TO CALCULATE FACTORIAL OF
|
|
||||||
20 REM SUPPLIED NUMBER N
|
|
||||||
30 INPUT "Please provide N: "; N
|
|
||||||
35 REM OUTPUT IS NOW A RESERVED KEYWORD
|
|
||||||
40 OUTPUTVAL = 1
|
|
||||||
50 FOR I = 1 TO N
|
|
||||||
60 OUTPUTVAL = OUTPUTVAL * I
|
|
||||||
70 NEXT I
|
|
||||||
80 PRINT "Factorial of N is "; OUTPUTVAL
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
2 PRINT TAB(34);"LIFE"
|
|
||||||
4 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN NEW JERSEY"
|
|
||||||
6 PRINT: PRINT: PRINT
|
|
||||||
8 PRINT "ENTER YOUR PATTERN, AS A SERIES OF SPACES"
|
|
||||||
9 PRINT "AND STARS, LINE BY LINE. FINISH BY TYPING"
|
|
||||||
10 PRINT "'DONE' ON THE FINAL LINE:"
|
|
||||||
11 X1=1: Y1=1: X2=24: Y2=70: G=0: P=0
|
|
||||||
12 DIM A(24, 70): DIM B$(24)
|
|
||||||
15 I9=1
|
|
||||||
20 C=1
|
|
||||||
30 INPUT TEMP$
|
|
||||||
35 B$(C) = TEMP$
|
|
||||||
40 IF B$(C)="DONE" THEN 45 ELSE 50
|
|
||||||
45 B$(C)="": GOTO 80
|
|
||||||
46 REM ORIGINAL VERSION REQUIRED USER TO WRITE
|
|
||||||
47 REM DOTS INSTEAD OF SPACES, WHICH WOULD THEN BE
|
|
||||||
48 REM CONVERTED TO SPACES
|
|
||||||
50 REM IF LEFT$(B$(C), 1)="." THEN 55 ELSE 60
|
|
||||||
55 REM B$(C)=" "+RIGHT$(B$(C), LEN(B$(C))-1)
|
|
||||||
60 C=C+1
|
|
||||||
70 GOTO 30
|
|
||||||
80 C=C-1: L=0
|
|
||||||
90 FOR X=1 TO C-1
|
|
||||||
100 IF LEN(B$(X))>L THEN 105 ELSE 110
|
|
||||||
105 L=LEN(B$(X))
|
|
||||||
110 NEXT X
|
|
||||||
120 X1=INT(11-C/2)
|
|
||||||
130 Y1=INT(33-L/2)
|
|
||||||
135 REM TRANSCRIBE INPUT PATTERN INTO ARRAY
|
|
||||||
140 FOR X=1 TO C
|
|
||||||
150 FOR Y=1 TO LEN(B$(X))
|
|
||||||
160 IF MID$(B$(X), Y, 1)<>" " THEN 165 ELSE 170
|
|
||||||
165 A(X1+X, Y1+Y)=1: P=P+1
|
|
||||||
170 NEXT Y
|
|
||||||
180 NEXT X
|
|
||||||
200 PRINT: PRINT: PRINT
|
|
||||||
210 PRINT "GENERATION: "; G; " POPULATION: "; P;
|
|
||||||
212 IF I9=0 THEN 213 ELSE 215
|
|
||||||
213 PRINT " INVALID!";
|
|
||||||
215 X3=24: Y3=70: X4=1: Y4=1: P=0
|
|
||||||
220 G=G+1
|
|
||||||
230 FOR X=X1 TO X2
|
|
||||||
240 PRINT
|
|
||||||
250 FOR Y=Y1 TO Y2
|
|
||||||
253 IF A(X, Y)=2 THEN 254 ELSE 256
|
|
||||||
254 A(X, Y)=0: GOTO 270
|
|
||||||
256 IF A(X, Y)=3 THEN 258 ELSE 260
|
|
||||||
258 A(X, Y)=1: GOTO 261
|
|
||||||
260 IF A(X, Y)<>1 THEN 270
|
|
||||||
261 PRINT TAB(Y);"*";
|
|
||||||
262 IF X<X3 THEN 263 ELSE 264
|
|
||||||
263 X3=X
|
|
||||||
264 IF X>X4 THEN 265 ELSE 266
|
|
||||||
265 X4=X
|
|
||||||
266 IF Y<Y3 THEN 267 ELSE 268
|
|
||||||
267 Y3=Y
|
|
||||||
268 IF Y>Y4 THEN 269 ELSE 270
|
|
||||||
269 Y4=Y
|
|
||||||
270 NEXT Y
|
|
||||||
290 NEXT X
|
|
||||||
295 FOR X=X2+1 TO 24
|
|
||||||
296 PRINT
|
|
||||||
297 NEXT X
|
|
||||||
299 X1=X3: X2=X4: Y1=Y3: Y2=Y4
|
|
||||||
301 IF X1<3 THEN 302 ELSE 303
|
|
||||||
302 X1=3: I9=-1
|
|
||||||
303 IF X2>22 THEN 304 ELSE 305
|
|
||||||
304 X2=22: I9=-1
|
|
||||||
305 IF Y1<3 THEN 306 ELSE 307
|
|
||||||
306 Y1=3: I9=-1
|
|
||||||
307 IF Y2>68 THEN 308 ELSE 309
|
|
||||||
308 Y2=68: I9=-1
|
|
||||||
309 P=0
|
|
||||||
500 FOR X=X1-1 TO X2+1
|
|
||||||
510 FOR Y=Y1-1 TO Y2+1
|
|
||||||
520 C=0
|
|
||||||
530 FOR I=X-1 TO X+1
|
|
||||||
540 FOR J=Y-1 TO Y+1
|
|
||||||
550 IF A(I, J)=1 OR A(I, J)=2 THEN 555 ELSE 560
|
|
||||||
555 C=C+1
|
|
||||||
560 NEXT J
|
|
||||||
570 NEXT I
|
|
||||||
580 IF A(X, Y)=0 THEN 610
|
|
||||||
590 IF C<3 or C>4 THEN 592 ELSE 595
|
|
||||||
592 A(X, Y)=2: GOTO 600
|
|
||||||
595 P=P+1
|
|
||||||
600 GOTO 620
|
|
||||||
610 IF C=3 THEN 615 ELSE 620
|
|
||||||
615 A(X, Y)=3: P=P+1
|
|
||||||
620 NEXT Y
|
|
||||||
630 NEXT X
|
|
||||||
635 X1=X1-1: Y1=Y1-1: X2=X2+1: Y2=Y2+1
|
|
||||||
640 GOTO 210
|
|
||||||
650 END
|
|
||||||
|
|
@ -1,720 +0,0 @@
|
||||||
10 REM PROGRAM NAME - OREGON VERSION:01/01/78
|
|
||||||
20 REM ORIGINAL PROGRAMMING BY BILL HEINEMANN - 1971
|
|
||||||
30 REM SUPPORT RESEARCH AND MATERIALS BY DON RAVITSCH,
|
|
||||||
40 REM MINNESOTA EDUCATIONAL COMPUTING CONSORTIUM STAFF
|
|
||||||
50 REM CDC CYBER 70/73-26 BASIC 3.1
|
|
||||||
60 REM DOCUMENTATION BOOKLET 'OREGON' AVAILABLE FROM
|
|
||||||
61 REM MECC SUPPORT SERVICES
|
|
||||||
62 REM 2520 BROADWAY DRIVE
|
|
||||||
63 REM ST. PAUL MN 55113
|
|
||||||
80 REM
|
|
||||||
150 REM *FOR THE MEANING OF THE VARIABLES USED, LIST LINES 6470-6790*
|
|
||||||
155 REM
|
|
||||||
160 PRINT "DO YOU NEED INSTRUCTIONS (YES/NO)" ;
|
|
||||||
165 REM PYBASIC CAN'T DO STRING OPERATIONS ON ARRAYS
|
|
||||||
170 REM DIM C$(5)
|
|
||||||
180 REM RANDOMIZE REMOVED
|
|
||||||
190 INPUT C$
|
|
||||||
200 IF C$ = "NO" THEN 690
|
|
||||||
210 PRINT
|
|
||||||
220 PRINT
|
|
||||||
230 REM ***INSTRUCTIONS***
|
|
||||||
240 PRINT "THIS PROGRAM SIMULATES A TRIP OVER THE OREGON TRAIL FROM"
|
|
||||||
250 PRINT "INDEPENDENCE, MISSOURI TO OREGON CITY, OREGON IN 1847."
|
|
||||||
260 PRINT "YOUR FAMILY OF FIVE WILL COVER THE 2040 MILE OREGON TRAIL"
|
|
||||||
270 PRINT "IN 5-6 MONTHS --- IF YOU MAKE IT ALIVE."
|
|
||||||
280 PRINT
|
|
||||||
290 PRINT "YOU HAD SAVED $900 TO SPEND FOR THE TRIP, AND YOU'VE JUST"
|
|
||||||
300 PRINT " PAID $200 FOR A WAGON."
|
|
||||||
310 PRINT "YOU WILL NEED TO SPEND THE REST OF YOUR MONEY ON THE"
|
|
||||||
320 PRINT " FOLLOWING ITEMS:"
|
|
||||||
330 PRINT
|
|
||||||
340 PRINT " OXEN - YOU CAN SPEND $200-$300 ON YOUR TEAM"
|
|
||||||
350 PRINT " THE MORE YOU SPEND, THE FASTER YOU'LL GO"
|
|
||||||
360 PRINT " BECAUSE YOU'LL HAVE BETTER ANIMALS"
|
|
||||||
370 PRINT
|
|
||||||
380 PRINT " FOOD - THE MORE YOU HAVE, THE LESS CHANCE THERE"
|
|
||||||
390 PRINT " IS OF GETTING SICK"
|
|
||||||
400 PRINT
|
|
||||||
410 PRINT " AMMUNITION - $1 BUYS A BELT OF 50 BULLETS"
|
|
||||||
420 PRINT " YOU WILL NEED BULLETS FOR ATTACKS BY ANIMALS"
|
|
||||||
430 PRINT " AND BANDITS, AND FOR HUNTING FOOD"
|
|
||||||
440 PRINT
|
|
||||||
450 PRINT " CLOTHING - THIS IS ESPECIALLY IMPORTANT FOR THE COLD"
|
|
||||||
460 PRINT " WEATHER YOU WILL ENCOUNTER WHEN CROSSING"
|
|
||||||
470 PRINT " THE MOUNTAINS"
|
|
||||||
480 PRINT
|
|
||||||
490 PRINT " MISCELLANEOUS SUPPLIES - THIS INCLUDES MEDICINE AND"
|
|
||||||
500 PRINT " OTHER THINGS YOU WILL NEED FOR SICKNESS"
|
|
||||||
510 PRINT " AND EMERGENCY REPAIRS"
|
|
||||||
520 PRINT
|
|
||||||
530 PRINT
|
|
||||||
540 PRINT "YOU CAN SPEND ALL YOUR MONEY BEFORE YOU START YOUR TRIP -"
|
|
||||||
550 PRINT "OR YOU CAN SAVE SOME OF YOUR CASH TO SPEND AT FORTS ALONG"
|
|
||||||
560 PRINT "THE WAY WHEN YOU RUN LOW. HOWEVER, ITEMS COST MORE AT"
|
|
||||||
570 PRINT "THE FORTS. YOU CAN ALSO GO HUNTING ALONG THE WAY TO GET"
|
|
||||||
580 PRINT "MORE FOOD."
|
|
||||||
590 PRINT "WHENEVER YOU HAVE TO USE YOUR TRUSTY RIFLE ALONG THE WAY,"
|
|
||||||
600 PRINT "YOU WILL BE TOLD TO TYPE IN A WORD (ONE THAT SOUNDS LIKE A "
|
|
||||||
610 PRINT "GUN SHOT). THE FASTER YOU TYPE IN THAT WORD AND HIT THE"
|
|
||||||
620 PRINT "" "RETURN" " KEY, THE BETTER LUCK YOU'LL HAVE WITH YOUR GUN."
|
|
||||||
630 PRINT
|
|
||||||
640 PRINT "AT EACH TURN, ALL ITEMS ARE SHOWN IN DOLLAR AMOUNTS"
|
|
||||||
650 PRINT "EXCEPT BULLETS"
|
|
||||||
660 PRINT "WHEN ASKED TO ENTER MONEY AMOUNTS, DON'T USE A " "$" "."
|
|
||||||
670 PRINT
|
|
||||||
680 PRINT "GOOD LUCK!!!"
|
|
||||||
690 PRINT
|
|
||||||
700 PRINT
|
|
||||||
710 PRINT "HOW GOOD A SHOT ARE YOU WITH YOUR RIFLE?"
|
|
||||||
720 PRINT " (1) ACE MARKSMAN, (2) GOOD SHOT, (3) FAIR TO MIDDLIN'"
|
|
||||||
730 PRINT " (4) NEED MORE PRACTICE, (5) SHAKY KNEES"
|
|
||||||
740 PRINT "ENTER ONE OF THE ABOVE -- THE BETTER YOU CLAIM YOU ARE, THE"
|
|
||||||
750 PRINT "FASTER YOU'LL HAVE TO BE WITH YOUR GUN TO BE SUCCESSFUL."
|
|
||||||
760 INPUT D9
|
|
||||||
770 IF D9 > 5 THEN 790
|
|
||||||
780 GOTO 810
|
|
||||||
790 D9 = 0
|
|
||||||
800 REM ***INITIAL PURCHASES***
|
|
||||||
810 X1 = - 1
|
|
||||||
820 REM LINES 820-829 MODIFIED BY CHRISTOPHER PEDERSEN (AUG 10, 2018)
|
|
||||||
821 REM FOR COMPATIBILITY WITH THE CHIPMUNK BASIC INTERPRETER
|
|
||||||
822 REM CHIPMUNK BASIC: http://www.nicholson.com/rhn/basic/
|
|
||||||
823 D3 = 0
|
|
||||||
824 M9 = 0
|
|
||||||
825 M = 0
|
|
||||||
826 F2 = 0
|
|
||||||
827 F1 = 0
|
|
||||||
828 S4 = 0
|
|
||||||
829 K8 = 0
|
|
||||||
830 PRINT
|
|
||||||
840 PRINT
|
|
||||||
850 PRINT "HOW MUCH DO YOU WANT TO SPEND ON YOUR OXEN TEAM" ;
|
|
||||||
860 INPUT A
|
|
||||||
870 IF A >= 200 THEN 900
|
|
||||||
880 PRINT "NOT ENOUGH"
|
|
||||||
890 GOTO 850
|
|
||||||
900 IF A <= 300 THEN 930
|
|
||||||
910 PRINT "TOO MUCH"
|
|
||||||
920 GOTO 850
|
|
||||||
930 PRINT "HOW MUCH DO YOU WANT TO SPEND ON FOOD" ;
|
|
||||||
940 INPUT F
|
|
||||||
950 IF F >= 0 THEN 980
|
|
||||||
960 PRINT "IMPOSSIBLE"
|
|
||||||
970 GOTO 930
|
|
||||||
980 PRINT "HOW MUCH DO YOU WANT TO SPEND ON AMMUNITION" ;
|
|
||||||
990 INPUT B
|
|
||||||
1000 IF B >= 0 THEN 1030
|
|
||||||
1010 PRINT "IMPOSSIBLE"
|
|
||||||
1020 GOTO 980
|
|
||||||
1030 PRINT "HOW MUCH DO YOU WANT TO SPEND ON CLOTHING" ;
|
|
||||||
1040 INPUT C
|
|
||||||
1050 IF C >= 0 THEN 1080
|
|
||||||
1060 PRINT "IMPOSSIBLE"
|
|
||||||
1070 GOTO 1030
|
|
||||||
1080 PRINT "HOW MUCH DO YOU WANT TO SPEND ON MISCELLANEOUS SUPPLIES" ;
|
|
||||||
1090 INPUT M1
|
|
||||||
1100 IF M1 >= 0 THEN 1130
|
|
||||||
1110 PRINT "IMPOSSIBLE"
|
|
||||||
1120 GOTO 1080
|
|
||||||
1130 T = 700 - A - F - B - C - M1
|
|
||||||
1140 IF T >= 0 THEN 1170
|
|
||||||
1150 PRINT "YOU OVERSPENT--YOU ONLY HAD $700 TO SPEND. BUY AGAIN"
|
|
||||||
1160 GOTO 830
|
|
||||||
1170 B = 50 * B
|
|
||||||
1180 PRINT "AFTER ALL YOUR PURCHASES. YOU NOW HAVE " ; T ; " DOLLARS LEFT"
|
|
||||||
1190 PRINT
|
|
||||||
1200 PRINT "MONDAY MARCH 29 1847"
|
|
||||||
1210 PRINT
|
|
||||||
1220 GOTO 1750
|
|
||||||
1230 IF M >= 2040 THEN 5430
|
|
||||||
1240 REM ***SETTING DATE***
|
|
||||||
1250 D3 = D3 + 1
|
|
||||||
1260 PRINT
|
|
||||||
1270 PRINT "MONDAY " ;
|
|
||||||
1280 IF D3 > 10 THEN 1300
|
|
||||||
1290 ON D3 GOTO 1310 , 1330 , 1350 , 1370 , 1390 , 1410 , 1430 , 1450 , 1470 , 1490
|
|
||||||
1300 ON D3 - 10 GOTO 1510 , 1530 , 1550 , 1570 , 1590 , 1610 , 1630 , 1650 , 1670 , 1690
|
|
||||||
1310 PRINT "APRIL 12 " ;
|
|
||||||
1320 GOTO 1720
|
|
||||||
1330 PRINT "APRIL 26 " ;
|
|
||||||
1340 GOTO 1720
|
|
||||||
1350 PRINT "MAY 10 " ;
|
|
||||||
1360 GOTO 1720
|
|
||||||
1370 PRINT "MAY 24 " ;
|
|
||||||
1380 GOTO 1720
|
|
||||||
1390 PRINT "JUNE 7 " ;
|
|
||||||
1400 GOTO 1720
|
|
||||||
1410 PRINT "JUNE 21 " ;
|
|
||||||
1420 GOTO 1720
|
|
||||||
1430 PRINT "JULY 5 " ;
|
|
||||||
1440 GOTO 1720
|
|
||||||
1450 PRINT "JULY 19 " ;
|
|
||||||
1460 GOTO 1720
|
|
||||||
1470 PRINT "AUGUST 2 " ;
|
|
||||||
1480 GOTO 1720
|
|
||||||
1490 PRINT "AUGUST 16 " ;
|
|
||||||
1500 GOTO 1720
|
|
||||||
1510 PRINT "AUGUST 31 " ;
|
|
||||||
1520 GOTO 1720
|
|
||||||
1530 PRINT "SEPTEMBER 13 " ;
|
|
||||||
1540 GOTO 1720
|
|
||||||
1550 PRINT "SEPTEMBER 27 " ;
|
|
||||||
1560 GOTO 1720
|
|
||||||
1570 PRINT "OCTOBER 11 " ;
|
|
||||||
1580 GOTO 1720
|
|
||||||
1590 PRINT "OCTOBER 25 " ;
|
|
||||||
1600 GOTO 1720
|
|
||||||
1610 PRINT "NOVEMBER 8 " ;
|
|
||||||
1620 GOTO 1720
|
|
||||||
1630 PRINT "NOVEMBER 22 " ;
|
|
||||||
1640 GOTO 1720
|
|
||||||
1650 PRINT "DECEMBER 6 " ;
|
|
||||||
1660 GOTO 1720
|
|
||||||
1670 PRINT "DECEMBER 20 " ;
|
|
||||||
1680 GOTO 1720
|
|
||||||
1690 PRINT "YOU HAVE BEEN ON THE TRAIL TOO LONG ------"
|
|
||||||
1700 PRINT "YOUR FAMILY DIES IN THE FIRST BLIZZARD OF WINTER"
|
|
||||||
1710 GOTO 5170
|
|
||||||
1720 PRINT "1847"
|
|
||||||
1730 PRINT
|
|
||||||
1740 REM ***BEGINNING EACH TURN***
|
|
||||||
1750 IF F >= 0 THEN 1770
|
|
||||||
1760 F = 0
|
|
||||||
1770 IF B >= 0 THEN 1790
|
|
||||||
1780 B = 0
|
|
||||||
1790 IF C >= 0 THEN 1810
|
|
||||||
1800 C = 0
|
|
||||||
1810 IF M1 >= 0 THEN 1830
|
|
||||||
1820 M1 = 0
|
|
||||||
1830 IF F >= 13 THEN 1850
|
|
||||||
1840 PRINT "YOU'D BETTER DO SOME HUNTING OR BUY FOOD AND SOON!!!!"
|
|
||||||
1850 F = INT ( F )
|
|
||||||
1860 B = INT ( B )
|
|
||||||
1870 C = INT ( C )
|
|
||||||
1880 M1 = INT ( M1 )
|
|
||||||
1890 T = INT ( T )
|
|
||||||
1900 M = INT ( M )
|
|
||||||
1910 M2 = M
|
|
||||||
1920 IF S4 = 1 THEN 1950
|
|
||||||
1930 IF K8 = 1 THEN 1950
|
|
||||||
1940 GOTO 1990
|
|
||||||
1950 T = T - 20
|
|
||||||
1960 IF T < 0 THEN 5080
|
|
||||||
1970 PRINT "DOCTOR'S BILL IS $20"
|
|
||||||
1980 REM LINES 1980-1982 MODIFIED BY C.D.P. FOR COMPATIBILITY WITH MODERN BASIC
|
|
||||||
1981 LET S4 = 0
|
|
||||||
1982 LET K8 = S4
|
|
||||||
1990 IF M9 = 1 THEN 2020
|
|
||||||
2000 PRINT "TOTAL MILEAGE: " ; M
|
|
||||||
2010 GOTO 2040
|
|
||||||
2020 PRINT "TOTAL MILEAGE: 950"
|
|
||||||
2030 M9 = 0
|
|
||||||
2040 REM LINES 2040-2050 MODIFIED BY C.D.P. FOR COMPATIBILITY WITH MODERN BASIC
|
|
||||||
2041 PRINT "FOOD: " ; F
|
|
||||||
2042 PRINT "BULLETS: " ; B
|
|
||||||
2043 PRINT "CLOTHING: " ; C
|
|
||||||
2044 PRINT "MISC. SUPPLIES: " ; M1
|
|
||||||
2050 PRINT "CASH: $" ; T
|
|
||||||
2060 IF X1 = - 1 THEN 2170
|
|
||||||
2070 X1 = X1 * ( - 1 )
|
|
||||||
2080 PRINT "DO YOU WANT TO (1) STOP AT THE NEXT FORT, (2) HUNT, " ;
|
|
||||||
2090 PRINT "OR (3) CONTINUE"
|
|
||||||
2100 INPUT X
|
|
||||||
2110 REM IF X>2 THEN 2150
|
|
||||||
2120 REM IF X<1 THEN 2150
|
|
||||||
2130 REM LET X=INT(X)
|
|
||||||
2140 GOTO 2270
|
|
||||||
2150 LET X = 3
|
|
||||||
2160 GOTO 2270
|
|
||||||
2170 PRINT "DO YOU WANT TO (1) HUNT, OR (2) CONTINUE"
|
|
||||||
2180 INPUT X
|
|
||||||
2190 IF X = 1 THEN 2210
|
|
||||||
2200 LET X = 2
|
|
||||||
2210 LET X = X + 1
|
|
||||||
2220 IF X = 3 THEN 2260
|
|
||||||
2230 IF B > 39 THEN 2260
|
|
||||||
2240 PRINT "TOUGH---YOU NEED MORE BULLETS TO GO HUNTING"
|
|
||||||
2250 GOTO 2170
|
|
||||||
2260 X1 = X1 * ( - 1 )
|
|
||||||
2270 ON X GOTO 2290 , 2540 , 2720
|
|
||||||
2280 REM ***STOPPING AT FORT***
|
|
||||||
2290 PRINT "ENTER WHAT YOU WISH TO SPEND ON THE FOLLOWING"
|
|
||||||
2300 PRINT "FOOD" ;
|
|
||||||
2310 GOSUB 2330
|
|
||||||
2320 GOTO 2410
|
|
||||||
2330 INPUT P
|
|
||||||
2340 IF P < 0 THEN 2400
|
|
||||||
2350 T = T - P
|
|
||||||
2360 IF T >= 0 THEN 2400
|
|
||||||
2370 PRINT "YOU DON'T HAVE THAT MUCH--KEEP YOUR SPENDING DOWN"
|
|
||||||
2380 T = T + P
|
|
||||||
2390 P = 0
|
|
||||||
2400 RETURN
|
|
||||||
2410 F = F + 2 / 3 * P
|
|
||||||
2420 PRINT "AMMUNITION" ;
|
|
||||||
2430 GOSUB 2330
|
|
||||||
2440 LET B = INT ( B + 2 / 3 * P * 50 )
|
|
||||||
2450 PRINT "CLOTHING" ;
|
|
||||||
2460 GOSUB 2330
|
|
||||||
2470 C = C + 2 / 3 * P
|
|
||||||
2480 PRINT "MISCELLANEOUS SUPPLIES" ;
|
|
||||||
2490 GOSUB 2330
|
|
||||||
2500 M1 = M1 + 2 / 3 * P
|
|
||||||
2510 M = M - 45
|
|
||||||
2520 GOTO 2720
|
|
||||||
2530 REM ***HUNTING***
|
|
||||||
2540 IF B > 39 THEN 2570
|
|
||||||
2550 PRINT "TOUGH---YOU NEED MORE BULLETS TO GO HUNTING"
|
|
||||||
2560 GOTO 2080
|
|
||||||
2570 M = M - 45
|
|
||||||
2580 GOSUB 6140
|
|
||||||
2590 IF B1 <= 1 THEN 2660
|
|
||||||
2600 IF 100 + RND ( 1 ) < 13 * B1 THEN 2710
|
|
||||||
2610 F = F + 48 - 2 * B1
|
|
||||||
2620 PRINT "NICE SHOT--RIGHT ON TARGET--GOOD EATIN' TONIGHT!!"
|
|
||||||
2630 B = B - 10 - 3 * B1
|
|
||||||
2640 GOTO 2720
|
|
||||||
2650 REM **BELLS IN LINE 2660**
|
|
||||||
2660 PRINT "RIGHT BETWEEN THE EYES---YOU GOT A BIG ONE!!!!"
|
|
||||||
2670 PRINT "FULL BELLIES TONIGHT!"
|
|
||||||
2680 F = F + 52 + RND ( 1 ) * 6
|
|
||||||
2690 B = B - 10 - RND ( 1 ) * 4
|
|
||||||
2700 GOTO 2720
|
|
||||||
2710 PRINT "YOU MISSED---AND YOUR DINNER GOT AWAY....."
|
|
||||||
2720 IF F >= 13 THEN 2750
|
|
||||||
2730 GOTO 5060
|
|
||||||
2740 REM ***EATING***
|
|
||||||
2750 PRINT "DO YOU WANT TO EAT (1) POORLY (2) MODERATELY"
|
|
||||||
2760 PRINT "OR (3) WELL" ;
|
|
||||||
2770 INPUT E
|
|
||||||
2780 IF E > 3 THEN 2750
|
|
||||||
2790 IF E < 1 THEN 2750
|
|
||||||
2800 LET E = INT ( E )
|
|
||||||
2810 LET F = F - 8 - 5 * E
|
|
||||||
2820 IF F >= 0 THEN 2860
|
|
||||||
2830 F = F + 8 + 5 * E
|
|
||||||
2840 PRINT "YOU CAN'T EAT THAT WELL"
|
|
||||||
2850 GOTO 2750
|
|
||||||
2860 LET M = M + 200 + ( A - 220 ) / 5 + 10 * RND ( 1 )
|
|
||||||
2870 REM LINES 2870-2872 MODIFIED BY C.D.P. FOR COMPATIBILITY W/ CHIPMUNK BASIC
|
|
||||||
2871 C1 = 0
|
|
||||||
2872 L1 = C1
|
|
||||||
2880 REM ***RIDERS ATTACK***
|
|
||||||
2889 REM LINE 2890 MODIFIED BY C.D.P. FOR COMPATIBILITY WITH CHIPMUNK BASIC
|
|
||||||
2900 PRINT "RIDERS AHEAD. THEY " ;
|
|
||||||
2910 S5 = 0
|
|
||||||
2919 REM ALL RND(-1) FUNCTION CALLS HAVE BEEN CHANGED TO RND(1) BY C.D.P.
|
|
||||||
2930 PRINT "DON'T " ;
|
|
||||||
2940 S5 = 1
|
|
||||||
2950 PRINT "LOOK HOSTILE"
|
|
||||||
2960 PRINT "TACTICS"
|
|
||||||
2970 PRINT "(1) RUN (2) ATTACK (3) CONTINUE (4) CIRCLE WAGONS"
|
|
||||||
2990 S5 = 1 - S5
|
|
||||||
3000 INPUT T1
|
|
||||||
3010 IF T1 < 1 THEN 2970
|
|
||||||
3020 IF T1 > 4 THEN 2970
|
|
||||||
3030 T1 = INT ( T1 )
|
|
||||||
3040 IF S5 = 1 THEN 3330
|
|
||||||
3050 IF T1 > 1 THEN 3110
|
|
||||||
3060 M = M + 20
|
|
||||||
3070 M1 = M1 - 15
|
|
||||||
3080 B = B - 150
|
|
||||||
3090 A = A - 40
|
|
||||||
3100 GOTO 3470
|
|
||||||
3110 IF T1 > 2 THEN 3240
|
|
||||||
3120 GOSUB 6140
|
|
||||||
3130 B = B - B1 * 40 - 80
|
|
||||||
3140 IF B1 > 1 THEN 3170
|
|
||||||
3150 PRINT "NICE SHOOTING---YOU DROVE THEM OFF"
|
|
||||||
3160 GOTO 3470
|
|
||||||
3170 IF B1 <= 4 THEN 3220
|
|
||||||
3180 PRINT "LOUSY SHOT---YOU GOT KNIFED"
|
|
||||||
3190 K8 = 1
|
|
||||||
3200 PRINT "YOU HAVE TO SEE OL' DOC BLANCHARD"
|
|
||||||
3210 GOTO 3470
|
|
||||||
3220 PRINT "KINDA SLOW WITH YOUR COLT .45"
|
|
||||||
3230 GOTO 3470
|
|
||||||
3240 IF T1 > 3 THEN 3290
|
|
||||||
3260 LET B = B - 150
|
|
||||||
3270 M1 = M1 - 15
|
|
||||||
3280 GOTO 3470
|
|
||||||
3290 GOSUB 6140
|
|
||||||
3300 B = B - B1 * 30 - 80
|
|
||||||
3310 M = M - 25
|
|
||||||
3320 GOTO 3140
|
|
||||||
3330 IF T1 > 1 THEN 3370
|
|
||||||
3340 M = M + 15
|
|
||||||
3350 A = A - 10
|
|
||||||
3360 GOTO 3470
|
|
||||||
3370 IF T1 > 2 THEN 3410
|
|
||||||
3380 M = M - 5
|
|
||||||
3390 B = B - 100
|
|
||||||
3400 GOTO 3470
|
|
||||||
3410 IF T1 > 3 THEN 3430
|
|
||||||
3420 GOTO 3470
|
|
||||||
3430 M = M - 20
|
|
||||||
3440 GOTO 3470
|
|
||||||
3450 PRINT "THEY DID NOT ATTACK"
|
|
||||||
3460 GOTO 3550
|
|
||||||
3470 IF S5 = 0 THEN 3500
|
|
||||||
3480 PRINT "RIDERS WERE FRIENDLY, BUT CHECK FOR POSSIBLE LOSSES"
|
|
||||||
3490 GOTO 3550
|
|
||||||
3500 PRINT "RIDERS WERE HOSTILE--CHECK FOR LOSES"
|
|
||||||
3510 IF B >= 0 THEN 3550
|
|
||||||
3520 PRINT "YOU RAN OUT OF BULLETS AND GOT MASSACRED BY THE RIDERS"
|
|
||||||
3530 GOTO 5170
|
|
||||||
3540 REM ***SELECTION OF EVENTS***
|
|
||||||
3550 LET D1 = 0
|
|
||||||
3560 RESTORE 3620
|
|
||||||
3570 R1 = 100 * RND ( 1 )
|
|
||||||
3580 LET D1 = D1 + 1
|
|
||||||
3590 IF D1 = 16 THEN 4670
|
|
||||||
3600 READ D
|
|
||||||
3610 IF R1 > D THEN 3580
|
|
||||||
3620 DATA 6 , 11 , 13 , 15 , 17 , 22 , 32 , 35 , 37 , 42 , 44 , 54 , 64 , 69 , 95
|
|
||||||
3630 IF D1 > 10 THEN 3650
|
|
||||||
3640 ON D1 GOTO 3660 , 3700 , 3740 , 3790 , 3820 , 3850 , 3880 , 3960 , 4130 , 4190
|
|
||||||
3650 ON D1 - 10 GOTO 4220 , 4290 , 4340 , 4560 , 4610 , 4670
|
|
||||||
3660 PRINT "WAGON BREAKS DOWN--LOSE TIME AND SUPPLIES FIXING IT"
|
|
||||||
3670 LET M = M - 15 - 5 * RND ( 1 )
|
|
||||||
3680 LET M1 = M1 - 8
|
|
||||||
3690 GOTO 4710
|
|
||||||
3700 PRINT "0X INJURES LEG---SLOWS YOU DOWN REST OF TRIP"
|
|
||||||
3710 LET M = M - 25
|
|
||||||
3720 LET A = A - 20
|
|
||||||
3730 GOTO 4710
|
|
||||||
3740 PRINT "BACK LUCK---YOUR DAUGHTER BROKE HER ARM"
|
|
||||||
3750 PRINT "YOU HAD TO STOP AND USE SUPPLIES TO MAKE A SLING"
|
|
||||||
3760 M = M - 5 - 4 * RND ( 1 )
|
|
||||||
3770 M1 = M1 - 2 - 3 * RND ( 1 )
|
|
||||||
3780 GOTO 4710
|
|
||||||
3790 PRINT "OX WANDERS OFF---SPEND TIME LOOKING FOR IT"
|
|
||||||
3800 M = M - 17
|
|
||||||
3810 GOTO 4710
|
|
||||||
3820 PRINT "YOUR SON GETS LOST---SPEND HALF THE DAY LOOKING FOR HIM"
|
|
||||||
3830 M = M - 10
|
|
||||||
3840 GOTO 4710
|
|
||||||
3850 PRINT "UNSAFE WATER--LOSE TIME LOOKING FOR CLEAN SPRING"
|
|
||||||
3860 LET M = M - 10 * RND ( 1 ) - 2
|
|
||||||
3870 GOTO 4710
|
|
||||||
3880 IF M > 950 THEN 4490
|
|
||||||
3890 PRINT "HEAVY RAINS---TIME AND SUPPLIES LOST"
|
|
||||||
3910 F = F - 10
|
|
||||||
3920 B = B - 500
|
|
||||||
3930 M1 = M1 - 15
|
|
||||||
3940 M = M - 10 * RND ( 1 ) - 5
|
|
||||||
3950 GOTO 4710
|
|
||||||
3960 PRINT "BANDITS ATTACK"
|
|
||||||
3970 GOSUB 6140
|
|
||||||
3980 B = B - 20 * B1
|
|
||||||
3990 IF B >= 0 THEN 4030
|
|
||||||
4000 PRINT "YOU RAN OUT OF BULLETS---THEY GET LOTS OF CASH"
|
|
||||||
4010 T = T / 3
|
|
||||||
4020 GOTO 4040
|
|
||||||
4030 IF B1 <= 1 THEN 4100
|
|
||||||
4040 PRINT "YOU GOT SHOT IN THE LEG AND THEY TOOK ONE OF YOUR OXEN"
|
|
||||||
4050 K8 = 1
|
|
||||||
4060 PRINT "BETTER HAVE A DOC LOOK AT YOUR WOUND"
|
|
||||||
4070 M1 = M1 - 5
|
|
||||||
4080 A = A - 20
|
|
||||||
4090 GOTO 4710
|
|
||||||
4100 PRINT "QUICKEST DRAW OUTSIDE OF DODGE CITY!!!"
|
|
||||||
4110 PRINT "YOU GOT 'EM!"
|
|
||||||
4120 GOTO 4710
|
|
||||||
4130 PRINT "THERE WAS A FIRE IN YOUR WAGON--FOOD AND SUPPLIES DAMAGE!"
|
|
||||||
4140 F = F - 40
|
|
||||||
4150 B = B - 400
|
|
||||||
4160 LET M1 = M1 - RND ( 1 ) * 8 - 3
|
|
||||||
4170 M = M - 15
|
|
||||||
4180 GOTO 4710
|
|
||||||
4190 PRINT "LOSE YOUR WAY IN HEAVY FOG---TIME IS LOST"
|
|
||||||
4200 M = M - 10 - 5 * RND ( 1 )
|
|
||||||
4210 GOTO 4710
|
|
||||||
4220 PRINT "YOU KILLED A POISONOUS SNAKE AFTER IT BIT YOU"
|
|
||||||
4230 B = B - 10
|
|
||||||
4240 M1 = M1 - 5
|
|
||||||
4250 IF M1 >= 0 THEN 4280
|
|
||||||
4260 PRINT "YOU DIE OF SNAKEBITE SINCE YOU HAVE NO MEDICINE"
|
|
||||||
4270 GOTO 5170
|
|
||||||
4280 GOTO 4710
|
|
||||||
4290 PRINT "WAGON GETS SWAMPED FORDING RIVER--LOSE FOOD AND CLOTHES"
|
|
||||||
4300 F = F - 30
|
|
||||||
4310 C = C - 20
|
|
||||||
4320 M = M - 20 - 20 * RND ( 1 )
|
|
||||||
4330 GOTO 4710
|
|
||||||
4340 PRINT "WILD ANIMALS ATTACK!"
|
|
||||||
4350 GOSUB 6140
|
|
||||||
4360 IF B > 39 THEN 4410
|
|
||||||
4370 PRINT "YOU WERE TOO LOW ON BULLETS--"
|
|
||||||
4380 PRINT "THE WOLVES OVERPOWERED YOU"
|
|
||||||
4390 K8 = 1
|
|
||||||
4400 GOTO 5120
|
|
||||||
4410 IF B1 > 2 THEN 4440
|
|
||||||
4420 PRINT "NICE SHOOTIN' PARTNER---THEY DIDN'T GET MUCH"
|
|
||||||
4430 GOTO 4450
|
|
||||||
4440 PRINT "SLOW ON THE DRAW---THEY GOT AT YOUR FOOD AND CLOTHES"
|
|
||||||
4450 B = B - 20 * B1
|
|
||||||
4460 C = C - B1 * 4
|
|
||||||
4470 F = F - B1 * 8
|
|
||||||
4480 GOTO 4710
|
|
||||||
4490 PRINT "COLD WEATHER---BRRRRRRR!---YOU " ;
|
|
||||||
4500 IF C > 22 + 4 * RND ( 1 ) THEN 4530
|
|
||||||
4510 PRINT "DON'T " ;
|
|
||||||
4520 C1 = 1
|
|
||||||
4530 PRINT "HAVE ENOUGH CLOTHING TO KEEP YOU WARM"
|
|
||||||
4540 IF C1 = 0 THEN 4710
|
|
||||||
4550 GOTO 6300
|
|
||||||
4560 PRINT "HAIL STORM---SUPPLIES DAMAGED"
|
|
||||||
4570 M = M - 5 - RND ( 1 ) * 10
|
|
||||||
4580 B = B - 200
|
|
||||||
4590 M1 = M1 - 4 - RND ( 1 ) * 3
|
|
||||||
4600 GOTO 4710
|
|
||||||
4610 IF E = 1 THEN 6300
|
|
||||||
4620 IF E = 3 THEN 4650
|
|
||||||
4630 IF RND(1) > 0.25 THEN 6300
|
|
||||||
4640 GOTO 4710
|
|
||||||
4650 IF RND(1) < 0.5 THEN 6300
|
|
||||||
4660 GOTO 4720
|
|
||||||
4670 PRINT "HELPFUL INDIANS SHOW YOU WHERE TO FIND MORE FOOD"
|
|
||||||
4680 F = F + 14
|
|
||||||
4690 GOTO 4710
|
|
||||||
4700 REM ***MOUNTAINS***
|
|
||||||
4710 IF M <= 950 THEN 1230
|
|
||||||
4719 REM LINE 4720 MODIFIED BY C.D.P. FOR COMPATIBILITY WITH CHIPMUNK BASIC
|
|
||||||
4720 IF RND(1)*10 > 9-(POW((M/100-15),2)+72)/(POW((M/100-15),2)+12) THEN 4860
|
|
||||||
4730 PRINT "RUGGED MOUNTAINS"
|
|
||||||
4740 IF RND(1) > 0.1 THEN 4780
|
|
||||||
4750 PRINT "YOU GOT LOST---LOSE VALUABLE TIME TRYING TO FIND TRAIL!"
|
|
||||||
4760 M = M - 60
|
|
||||||
4770 GOTO 4860
|
|
||||||
4780 IF RND(1) > 0.11 THEN 4840
|
|
||||||
4790 PRINT "WAGON DAMAGED!---LOSE TIME AND SUPPLIES"
|
|
||||||
4800 M1 = M1 - 5
|
|
||||||
4810 B = B - 200
|
|
||||||
4820 M = M - 20 - 30 * RND ( 1 )
|
|
||||||
4830 GOTO 4860
|
|
||||||
4840 PRINT "THE GOING GETS SLOW"
|
|
||||||
4850 M = M - 45 - RND(1) / 0.02
|
|
||||||
4860 IF F1 = 1 THEN 4900
|
|
||||||
4870 F1 = 1
|
|
||||||
4880 IF RND(1) < 0.8 THEN 4970
|
|
||||||
4890 PRINT "YOU MADE IT SAFELY THROUGH SOUTH PASS--NO SNOW"
|
|
||||||
4900 IF M < 1700 THEN 4940
|
|
||||||
4910 IF F2 = 1 THEN 4940
|
|
||||||
4920 F2 = 1
|
|
||||||
4930 IF RND(1) < 0.7 THEN 4970
|
|
||||||
4940 IF M > 950 THEN 1230
|
|
||||||
4950 M9 = 1
|
|
||||||
4960 GOTO 1230
|
|
||||||
4970 PRINT "BLIZZARD IN MOUNTAIN PASS--TIME AND SUPPLIES LOST"
|
|
||||||
4980 L1 = 1
|
|
||||||
4990 F = F - 25
|
|
||||||
5000 M1 = M1 - 10
|
|
||||||
5010 B = B - 300
|
|
||||||
5020 M = M - 30 - 40 * RND ( 1 )
|
|
||||||
5030 IF C < 18 + 2 * RND ( 1 ) THEN 6300
|
|
||||||
5040 GOTO 4940
|
|
||||||
5050 REM ***DYING***
|
|
||||||
5060 PRINT "YOU RAN OUT OF FOOD AND STARVED TO DEATH"
|
|
||||||
5070 GOTO 5170
|
|
||||||
5080 LET T = 0
|
|
||||||
5090 PRINT "YOU CAN'T AFFORD A DOCTOR"
|
|
||||||
5100 GOTO 5120
|
|
||||||
5110 PRINT "YOU RAN OUT OF MEDICAL SUPPLIES"
|
|
||||||
5120 PRINT "YOU DIED OF " ;
|
|
||||||
5130 IF K8 = 1 THEN 5160
|
|
||||||
5140 PRINT "PNEUMONIA"
|
|
||||||
5150 GOTO 5170
|
|
||||||
5160 PRINT "INJURIES"
|
|
||||||
5170 PRINT
|
|
||||||
5180 PRINT "DUE TO YOUR UNFORTUNATE SITUATION, THERE ARE A FEW"
|
|
||||||
5190 PRINT "FORMALITIES WE MUST GO THROUGH"
|
|
||||||
5200 PRINT
|
|
||||||
5210 PRINT "WOULD YOU LIKE A MINISTER?"
|
|
||||||
5220 INPUT C$
|
|
||||||
5230 PRINT "WOULD YOU LIKE A FANCY FUNERAL?"
|
|
||||||
5240 INPUT C$
|
|
||||||
5250 PRINT "WOULD YOU LIKE US TO INFORM YOUR NEXT OF KIN?"
|
|
||||||
5260 INPUT C$
|
|
||||||
5270 IF C$ = "YES" THEN 5310
|
|
||||||
5280 PRINT "BUT YOUR AUNT SADIE IN ST. LOUIS IS REALLY WORRIED ABOUT YOU"
|
|
||||||
5290 PRINT
|
|
||||||
5300 GOTO 5330
|
|
||||||
5310 PRINT "THAT WILL BE $4.50 FOR THE TELEGRAPH CHARGE."
|
|
||||||
5320 PRINT
|
|
||||||
5330 PRINT "WE THANK YOU FOR THIS INFORMATION AND WE ARE SORRY YOU"
|
|
||||||
5340 PRINT "DIDN'T MAKE IT TO THE GREAT TERRITORY OF OREGON"
|
|
||||||
5350 PRINT "BETTER LUCK NEXT TIME"
|
|
||||||
5360 PRINT
|
|
||||||
5370 PRINT
|
|
||||||
5380 PRINT TAB ( 30 ) ; "SINCERELY"
|
|
||||||
5390 PRINT
|
|
||||||
5400 PRINT TAB ( 17 ) ; "THE OREGON CITY CHAMBER OF COMMERCE"
|
|
||||||
5409 REM 'STOP' COMMAND BELOW CHANGED TO 'END' BY C.D.P.
|
|
||||||
5410 END
|
|
||||||
5420 REM ***FINAL TURN***
|
|
||||||
5430 F9 = ( 2040 - M2 ) / ( M - M2 )
|
|
||||||
5440 F = F + ( 1 - F9 ) * ( 8 + 5 * E )
|
|
||||||
5450 PRINT
|
|
||||||
5460 REM **BELLS IN LINES 5470,5480**
|
|
||||||
5470 PRINT "YOU FINALLY ARRIVED AT OREGON CITY"
|
|
||||||
5480 PRINT "AFTER 2040 LONG MILES---HOORAY!!!!!"
|
|
||||||
5490 PRINT "A REAL PIONEER!"
|
|
||||||
5500 PRINT
|
|
||||||
5510 F9 = INT ( F9 * 14 )
|
|
||||||
5520 D3 = D3 * 14 + F9
|
|
||||||
5530 F9 = F9 + 1
|
|
||||||
5540 IF F9 < 8 THEN 5560
|
|
||||||
5550 F9 = F9 - 7
|
|
||||||
5560 ON F9 GOTO 5570 , 5590 , 5610 , 5630 , 5650 , 5670 , 5690
|
|
||||||
5570 PRINT "MONDAY " ;
|
|
||||||
5580 GOTO 5700
|
|
||||||
5590 PRINT "TUESDAY " ;
|
|
||||||
5600 GOTO 5700
|
|
||||||
5610 PRINT "WEDNESDAY " ;
|
|
||||||
5620 GOTO 5700
|
|
||||||
5630 PRINT "THURSDAY " ;
|
|
||||||
5640 GOTO 5700
|
|
||||||
5650 PRINT "FRIDAY " ;
|
|
||||||
5660 GOTO 5700
|
|
||||||
5670 PRINT "SATURDAY " ;
|
|
||||||
5680 GOTO 5700
|
|
||||||
5690 PRINT "SUNDAY " ;
|
|
||||||
5700 IF D3 > 124 THEN 5740
|
|
||||||
5710 D3 = D3 - 93
|
|
||||||
5720 PRINT "JULY " ; D3 ; " 1847"
|
|
||||||
5730 GOTO 5920
|
|
||||||
5740 IF D3 > 155 THEN 5780
|
|
||||||
5750 D3 = D3 - 124
|
|
||||||
5760 PRINT "AUGUST " ; D3 ; " 1847"
|
|
||||||
5770 GOTO 5920
|
|
||||||
5780 IF D3 > 185 THEN 5820
|
|
||||||
5790 D3 = D3 - 155
|
|
||||||
5800 PRINT "SEPTEMBER " ; D3 ; " 1847"
|
|
||||||
5810 GOTO 5920
|
|
||||||
5820 IF D3 > 216 THEN 5860
|
|
||||||
5830 D3 = D3 - 185
|
|
||||||
5840 PRINT "OCTOBER " ; D3 ; " 1847"
|
|
||||||
5850 GOTO 5920
|
|
||||||
5860 IF D3 > 246 THEN 5900
|
|
||||||
5870 D3 = D3 - 216
|
|
||||||
5880 PRINT "NOVEMBER " ; D3 ; " 1847"
|
|
||||||
5890 GOTO 5920
|
|
||||||
5900 D3 = D3 - 246
|
|
||||||
5910 PRINT "DECEMBER " ; D3 ; " 1847"
|
|
||||||
5920 PRINT
|
|
||||||
5930 REM LINE 5930 REMOVED BY C.D.P. FOR COMPATIBILITY WITH MODERN BASIC
|
|
||||||
5940 IF B > 0 THEN 5960
|
|
||||||
5950 LET B = 0
|
|
||||||
5960 IF C > 0 THEN 5980
|
|
||||||
5970 LET C = 0
|
|
||||||
5980 IF M1 > 0 THEN 6000
|
|
||||||
5990 LET M1 = 0
|
|
||||||
6000 IF T > 0 THEN 6020
|
|
||||||
6010 LET T = 0
|
|
||||||
6020 IF F > 0 THEN 6040
|
|
||||||
6030 LET F = 0
|
|
||||||
6040 REM LINES 6040-6045 MODIFIED BY C.D.P. FOR COMPATIBILITY WITH MODERN BASIC
|
|
||||||
6041 PRINT "FOOD: " ; F
|
|
||||||
6042 PRINT "BULLETS: " ; B
|
|
||||||
6043 PRINT "CLOTHING: " ; C
|
|
||||||
6044 PRINT "MISC. SUPP.: " ; M1
|
|
||||||
6045 PRINT "CASH: " ; T
|
|
||||||
6050 PRINT
|
|
||||||
6060 PRINT TAB ( 11 ) ; "PRESIDENT JAMES K. POLK SENDS YOU HIS"
|
|
||||||
6070 PRINT TAB ( 17 ) ; "HEARTIEST CONGRATULATIONS"
|
|
||||||
6080 PRINT
|
|
||||||
6090 PRINT TAB ( 11 ) ; "AND WISHES YOU A PROSPEROUS LIFE AHEAD"
|
|
||||||
6100 PRINT
|
|
||||||
6110 PRINT TAB ( 22 ) ; "AT YOUR NEW HOME"
|
|
||||||
6119 REM 'STOP' COMMAND BELOW CHANGED TO 'END' BY C.D.P.
|
|
||||||
6120 END
|
|
||||||
6130 REM ***SHOOTING SUB-ROUTINE***
|
|
||||||
6131 REM THE METHOD OF TIMING THE SHOOTING (LINES 6210-6240)
|
|
||||||
6132 REM WILL VARY FROM SYSTEM TO SYSTEM. FOR EXAMPLE, H-P
|
|
||||||
6133 REM USERS WILL PROBABLY PREFER TO USE THE 'ENTER' STATEMENT.
|
|
||||||
6134 REM IF TIMING ON THE USER'S SYSTEM IS HIGHLY SUSCEPTIBLE
|
|
||||||
6135 REM TO SYSTEM RESPONSE TIME, THE FORMULA IN LINE 6240 CAN
|
|
||||||
6136 REM BE TAILORED TO ACCOMMODATE THIS BY EITHER INCREASING
|
|
||||||
6137 REM OR DECREASING THE 'SHOOTING' TIME RECORDED BY THE SYSTEM
|
|
||||||
6140 DIM S$ ( 5 )
|
|
||||||
6150 S$ ( 1 ) = "BANG"
|
|
||||||
6160 S$ ( 2 ) = "BLAM"
|
|
||||||
6170 S$ ( 3 ) = "POW"
|
|
||||||
6180 S$ ( 4 ) = "WHAM"
|
|
||||||
6190 S6 = INT ( RND ( 1 ) * 4 + 1 )
|
|
||||||
6200 PRINT "TYPE " ; S$ ( S6 )
|
|
||||||
6201 REM NO TIMER FUNCTION IN PYBASIC, SO RANDOM ELEMENT INTRODUCED
|
|
||||||
6202 REM I'M AWARE THAT THIS CHANGES THE ELEMENT OF 'SKILL' TO
|
|
||||||
6203 REM ONE OF LUCK FOR HUNTING
|
|
||||||
6206 REM 'CLK(0)' FUNCTION CHANGED TO 'TIMER' BY C.D.P. FOR COMPATIBILITY
|
|
||||||
6207 REM B3 = TIMER changed to B3 = TIMER + 2 BY C.D.P. TO MAKE HUNTING...
|
|
||||||
6208 REM ...EASIER ON MODERN COMPUTERS. SEE NOTES FROM ORIGINAL AUTHOR ON
|
|
||||||
6209 REM ... ON TWEAKING HUNTING DIFFICULTY
|
|
||||||
6210 REM B3 = TIMER + 2
|
|
||||||
6220 INPUT C$
|
|
||||||
6229 REM 'CLK(0)' FUNCTION CHANGED TO 'TIMER' BY C.D.P. FOR COMPATIBILITY
|
|
||||||
6230 REM B1 = TIMER
|
|
||||||
6240 REM B1 = ( ( B1 - B3 ) * 3600 ) - ( D9 - 1 )
|
|
||||||
6244 REM IT'S A PYBASIC BODGE, BUT GENERATE RANDOM B1
|
|
||||||
6245 B1 = INT(RND(1)*9)+1
|
|
||||||
6250 PRINT
|
|
||||||
6255 IF B1 > 0 THEN 6260
|
|
||||||
6257 B1 = 0
|
|
||||||
6260 IF C$ = S$ ( S6 ) THEN 6280
|
|
||||||
6270 B1 = 9
|
|
||||||
6280 RETURN
|
|
||||||
6290 REM ***ILLNESS SUB-ROUTINE***
|
|
||||||
6300 IF 100 * RND ( 1 ) < 10 + 35 * ( E - 1 ) THEN 6370
|
|
||||||
6309 REM LINE 6310 MODIFIED BY C.D.P. FOR COMPATIBILITY WITH CHIPMUNK BASIC
|
|
||||||
6310 IF 100*RND(1)<100-POW(40/4,E-1) THEN 6410
|
|
||||||
6320 PRINT "SERIOUS ILLNESS---"
|
|
||||||
6330 PRINT "YOU MUST STOP FOR MEDICAL ATTENTION"
|
|
||||||
6340 M1 = M1 - 10
|
|
||||||
6350 S4 = 1
|
|
||||||
6360 GOTO 6440
|
|
||||||
6370 PRINT "WILD ILLNESS---MEDICINE USED"
|
|
||||||
6380 M = M - 5
|
|
||||||
6390 M1 = M1 - 2
|
|
||||||
6400 GOTO 6440
|
|
||||||
6410 PRINT "BAD ILLNESS---MEDICINE USED"
|
|
||||||
6420 M = M - 5
|
|
||||||
6430 M1 = M1 - 5
|
|
||||||
6440 IF M1 < 0 THEN 5110
|
|
||||||
6450 IF L1 = 1 THEN 4940
|
|
||||||
6460 GOTO 4710
|
|
||||||
6470 REM ***IDENTIFICATION OF VARIABLES IN THE PROGRAM***
|
|
||||||
6480 REM A = AMOUNT SPENT ON ANIMALS
|
|
||||||
6490 REM B = AMOUNT SPENT ON AMMUNITION
|
|
||||||
6500 REM B1 = ACTUAL RESPONSE TIME FOR INPUTTING "BANG"
|
|
||||||
6510 REM B3 = CLOCK TIME AT START OF INPUTTING "BANG"
|
|
||||||
6520 REM C = AMOUNT SPENT ON CLOTHING
|
|
||||||
6530 REM C1 = FLAG FOR INSUFFICIENT CLOTHING IN COLD WEATHER
|
|
||||||
6540 REM C$ = YES/N0 RESPONSE TO QUESTIONS
|
|
||||||
6550 REM D1 = COUNTER IN GENERATING EVENTS
|
|
||||||
6560 REM D3 = TURN NUMBER FOR SETTING DATE
|
|
||||||
6570 REM D4 = CURRENT DATE
|
|
||||||
6580 REM D9 = CHOICE OF SHOOTING EXPERTISE LEVEL
|
|
||||||
6590 REM E = CHOICE OF EATING
|
|
||||||
6600 REM F = AMOUNT SPENT ON FOOD
|
|
||||||
6610 REM F1 = FLAG FOR CLEARING SOUTH PASS
|
|
||||||
6620 REM F2 = FLAG FOR CLEARING BLUE MOUNTAINS
|
|
||||||
6630 REM F9 = FRACTION OF 2 WEEKS TRAVELED ON FINAL TURN
|
|
||||||
6640 REM K8 = FLAG FOR INJURY
|
|
||||||
6650 REM L1 = FLAG FOR BLIZZARD
|
|
||||||
6660 REM M = TOTAL MILEAGE WHOLE TRIP
|
|
||||||
6670 REM M1 = AMOUNT SPENT ON MISCELLANEOUS SUPPLIES
|
|
||||||
6680 REM M2 = TOTAL MILEAGE UP THROUGH PREVIOUS TURN
|
|
||||||
6690 REM M9 = FLAG FOR CLEARING SOUTH PASS IN SETTING MILEAGE
|
|
||||||
6700 REM P = AMOUNT SPENT ON ITEMS AT FORT
|
|
||||||
6710 REM R1 = RANDOM NUMBER IN CHOOSING EVENTS
|
|
||||||
6720 REM S4 = FLAG FOR ILLNESS
|
|
||||||
6730 REM S5 = ""HOSTILITY OF RIDERS"" FACTOR
|
|
||||||
6740 REM S6 = SHOOTING WORD SELECTOR
|
|
||||||
6750 REM S$ = VARIATIONS OF SHOOTING WORD
|
|
||||||
6760 REM T = CASH LEFT OVER AFTER INITIAL PURCHASES
|
|
||||||
6770 REM T1 = CHOICE OF TACTICS WHEN ATTACKED
|
|
||||||
6780 REM X = CHOICE OF ACTION FOR EACH TURN
|
|
||||||
6790 REM X1 = FLAG FOR FORT OPTION
|
|
||||||
6800 END
|
|
||||||
|
|
@ -1,159 +0,0 @@
|
||||||
10 REM A BASIC PROGRAM THAT CAN BE USED FOR REGRESSION TESTING
|
|
||||||
20 REM OF ALL INTERPRETER FUNCTIONALITY
|
|
||||||
30 PRINT "*** Testing basic arithmetic functions and multiple statements ***"
|
|
||||||
40 LET I = 100: LET J = 200
|
|
||||||
60 PRINT "Expecting the sum to be 300:"
|
|
||||||
70 PRINT I + J
|
|
||||||
80 PRINT "Expecting the product to be 20000:"
|
|
||||||
90 PRINT I * J
|
|
||||||
100 PRINT "Expecting the sum to be 20100:"
|
|
||||||
110 PRINT 100 + I * J
|
|
||||||
120 PRINT "Expecting sum to be 40000"
|
|
||||||
130 PRINT (100 + I) * J
|
|
||||||
140 IF I > J THEN 150 ELSE 180
|
|
||||||
150 PRINT "Should not print the smaller value of I which is "; I
|
|
||||||
160 PRINT I
|
|
||||||
170 GOTO 180
|
|
||||||
180 PRINT "Should print the larger value of J which is "; J
|
|
||||||
190 PRINT J
|
|
||||||
200 GOTO 220
|
|
||||||
210 PRINT "Should not print this line"
|
|
||||||
220 PRINT "*** Testing subroutine behaviour ***"
|
|
||||||
230 PRINT "Calling subroutine"
|
|
||||||
240 GOSUB 1630
|
|
||||||
250 PRINT "Exited subroutine"
|
|
||||||
260 PRINT "Now testing nested subroutines"
|
|
||||||
270 GOSUB 1660
|
|
||||||
280 PRINT "*** Testing loops ***"
|
|
||||||
290 PRINT "This loop should count to 5 in increments of 1:"
|
|
||||||
300 FOR I = 1 TO 5
|
|
||||||
310 PRINT I
|
|
||||||
320 NEXT I
|
|
||||||
330 PRINT "This loop should count back from 10 to 1 in decrements of 2:"
|
|
||||||
340 FOR I = 10 TO 1 STEP -2
|
|
||||||
350 PRINT I
|
|
||||||
360 NEXT I
|
|
||||||
370 PRINT "These nested loops should print 11, 12, 13, 21, 22, 23:"
|
|
||||||
380 FOR I = 1 TO 2
|
|
||||||
390 FOR J = 1 TO 3
|
|
||||||
400 PRINT I; J
|
|
||||||
410 NEXT J
|
|
||||||
420 NEXT I
|
|
||||||
430 PRINT "*** Testing arrays ***"
|
|
||||||
440 DIM A(3, 3)
|
|
||||||
450 FOR I = 0 TO 2
|
|
||||||
460 FOR J = 0 TO 2
|
|
||||||
470 LET A(I, J) = 5
|
|
||||||
480 NEXT J
|
|
||||||
490 NEXT I
|
|
||||||
500 PRINT "This should print 555"
|
|
||||||
510 PRINT A(0, 0); A(1, 1); A(2, 2)
|
|
||||||
520 PRINT "*** Testing file i/o ***"
|
|
||||||
530 OPEN "REGRESSION.TXT" FOR OUTPUT AS #1
|
|
||||||
540 PRINT #1,"0123456789Hello World!"
|
|
||||||
545 PRINT #1,"This is second line for testing"
|
|
||||||
550 CLOSE #1
|
|
||||||
560 OPEN "REGRESSION.TXT" FOR INPUT AS #2
|
|
||||||
570 PRINT "The next line should say 'Hello World!'"
|
|
||||||
580 FSEEK #2,10
|
|
||||||
590 INPUT #2,A$
|
|
||||||
595 PRINT A$
|
|
||||||
600 CLOSE #2
|
|
||||||
601 OPEN "REGRESSION.TXT" FOR APPEND AS #2
|
|
||||||
602 PRINT "3 text lines starting with 0,T,S and ending with !,g,e should follow:"
|
|
||||||
603 PRINT #2,"Should be a seperate line"
|
|
||||||
604 CLOSE #2
|
|
||||||
605 OPEN "REGRESSION.TXT" FOR INPUT AS #2
|
|
||||||
606 FOR I = 1 TO 2
|
|
||||||
607 INPUT #2,A$:PRINT A$
|
|
||||||
608 NEXT I
|
|
||||||
609 INPUT #2,A$
|
|
||||||
610 FOR I = 1 TO 25
|
|
||||||
611 PRINT MID$(A$,I,1);
|
|
||||||
612 NEXT I
|
|
||||||
613 PRINT:CLOSE #2
|
|
||||||
614 OPEN "NOFILE.X7Z" FOR INPUT AS #2 ELSE 620
|
|
||||||
615 PRINT "***This Message should NOT be Displayed***"
|
|
||||||
620 N = 0
|
|
||||||
630 I = 7
|
|
||||||
640 PRINT "This loop should count to 5 in increments of 1 twice:"
|
|
||||||
650 FOR I = 1 TO 10
|
|
||||||
660 PRINT I
|
|
||||||
670 IF I = 5 THEN GOTO 690
|
|
||||||
680 NEXT I
|
|
||||||
690 N = N + 1
|
|
||||||
700 IF N < 2 THEN GOTO 650
|
|
||||||
810 PRINT "The loop variable I should be equal to 5, I=";I
|
|
||||||
815 DATA "DATA Statement tests..."
|
|
||||||
820 READ A$
|
|
||||||
825 PRINT "The next line should read: DATA Statement tests..."
|
|
||||||
830 PRINT A$
|
|
||||||
840 DATA 1 , 2 , 3
|
|
||||||
850 DATA 4 , 5 , 6
|
|
||||||
855 DATA 1.5 , 2 , "test"
|
|
||||||
858 PRINT "The next three lines should be: 12 34 56"
|
|
||||||
860 FOR I = 1 TO 3
|
|
||||||
870 READ J , K
|
|
||||||
880 PRINT J ; K
|
|
||||||
890 NEXT I
|
|
||||||
900 RESTORE 840
|
|
||||||
910 READ I , J , K
|
|
||||||
920 PRINT "the next line should print 123"
|
|
||||||
930 PRINT I ; J ; K
|
|
||||||
970 RESTORE 855
|
|
||||||
980 READ A1 , B , C$
|
|
||||||
990 PRINT "Float: " ; A1 ; " Int: " ; B ; " String: " ; C$
|
|
||||||
1000 RESTORE 850
|
|
||||||
1010 READ I , J , K , L
|
|
||||||
1020 PRINT "the next line should print 4561.5:"
|
|
||||||
1030 PRINT I; J ; K ; L
|
|
||||||
1040 PRINT "The next lines should print: 'Hello World' and then 'AGAIN' under the word 'World'"
|
|
||||||
1050 PRINT "Hel" ; : PRINT "lo" ; TAB ( 7 ) ; "World" ; TAB ( 7 ) ; "AGAIN"
|
|
||||||
1060 PRINT "This loop should count from 1 to 10"
|
|
||||||
1070 FOR I = 1 TO 10
|
|
||||||
1080 FOR J = 1 TO 3
|
|
||||||
1090 PRINT I
|
|
||||||
1100 GOTO 1130
|
|
||||||
1120 NEXT J
|
|
||||||
1130 NEXT I
|
|
||||||
1140 INPUT "Enter T for the THEN blocks to execute, E for the ELSE (T/E): " ; ANS$
|
|
||||||
1150 ANS$ = UPPER$ ( ANS$ )
|
|
||||||
1160 IF ANS$ = "T" THEN 1190
|
|
||||||
1170 PRINT "1170: Did not enter T"
|
|
||||||
1180 GOTO 1200
|
|
||||||
1190 PRINT "1190: Entered T"
|
|
||||||
1200 IF ANS$ = "T" THEN GOTO 1230
|
|
||||||
1210 PRINT "1210: Did not enter T"
|
|
||||||
1220 GOTO 1240
|
|
||||||
1230 PRINT "1230: Entered T"
|
|
||||||
1240 IF ANS$ = "T" THEN 1280 ELSE 1260
|
|
||||||
1250 PRINT "ERROR - Should not be at line 1250"
|
|
||||||
1260 PRINT "1260: Did not enter T"
|
|
||||||
1270 GOTO 1290
|
|
||||||
1280 PRINT "1280: Entered T"
|
|
||||||
1290 IF ANS$ = "T" THEN GOTO 1330 ELSE GOTO 1310
|
|
||||||
1300 PRINT "ERROR - Should not be at line 1300"
|
|
||||||
1310 PRINT "1310: Did not enter T"
|
|
||||||
1320 GOTO 1340
|
|
||||||
1330 PRINT "1330: Entered T"
|
|
||||||
1340 IF ANS$ = "T" THEN PRINT "1340: Entered T"
|
|
||||||
1350 IF ANS$ <> "T" THEN PRINT "1350: Did not enter T"
|
|
||||||
1360 IF ANS$ = "T" THEN PRINT "1360: Entered T" ELSE PRINT "1360: Did not enter T"
|
|
||||||
1370 IF ANS$ = "T" THEN PRINT "1370: Entered T" : GOTO 1390
|
|
||||||
1380 IF ANS$ <> "T" THEN PRINT "1380: Did not enter T"
|
|
||||||
1390 IF ANS$ = "T" THEN PRINT "1390: Entered " ; : PRINT "T" ELSE PRINT "1390: Did " ; : PRINT "not enter T"
|
|
||||||
1400 IF ANS$ = "T" THEN PRINT "1400: Entered T" ELSE PRINT "1400: Did " ; : PRINT "not enter T"
|
|
||||||
1410 IF ANS$ = "T" THEN PRINT "1410: Entered " ; : PRINT "T" ELSE PRINT "1410: Did not enter T"
|
|
||||||
1420 PRINT "Compound Stmt w/conditionals ";:IF ANS$ = "T" THEN PRINT "1420: Entered " ; : PRINT "T" ELSE PRINT "1420: Did " ; : PRINT "not enter T"
|
|
||||||
1610 PRINT "*** Finished ***"
|
|
||||||
1620 STOP
|
|
||||||
1630 REM A SUBROUTINE TEST
|
|
||||||
1640 PRINT "Executing the subroutine"
|
|
||||||
1650 RETURN
|
|
||||||
1660 REM AN OUTER SUBROUTINE
|
|
||||||
1670 GOSUB 1700
|
|
||||||
1680 PRINT "This should be printed second"
|
|
||||||
1690 RETURN
|
|
||||||
1700 REM A NESTED SUBROUTINE
|
|
||||||
1710 PRINT "This should be printed first"
|
|
||||||
1720 RETURN
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
10 REM ROCK, SCISSORS, PAPER AGAINST
|
|
||||||
20 REM THE COMPUTER
|
|
||||||
30 RANDOMIZE
|
|
||||||
40 MYSCORE = 0
|
|
||||||
50 YOURSCORE = 0
|
|
||||||
60 PRINT "Let's play rock-scissors-paper!"
|
|
||||||
70 INPUT "(R)ock, (S)cissors, (P)aper or e(X)it: "; YOURGUESS$
|
|
||||||
75 IF YOURGUESS$ = "X" THEN 160
|
|
||||||
80 RANDOM = RND(1)
|
|
||||||
90 GOSUB 190
|
|
||||||
100 PRINT "Your guess: "; YOURGUESS$; ", My guess: "; MYGUESS$
|
|
||||||
110 REM ON YOURGUESS$ = "R" GOSUB 300
|
|
||||||
120 REM ON YOURGUESS$ = "S" GOSUB 500
|
|
||||||
130 REM ON YOURGUESS$ = "P" GOSUB 700
|
|
||||||
135 ON INSTR("RSP",YOURGUESS$) GOSUB 300,500,700
|
|
||||||
150 GOTO 70
|
|
||||||
160 PRINT "My score: "; MYSCORE; " Your score: "; YOURSCORE
|
|
||||||
170 STOP
|
|
||||||
190 REM RANDOMLY ASSIGN MYGUESS$
|
|
||||||
200 IF RANDOM < 0.3 THEN 210 ELSE 230
|
|
||||||
210 MYGUESS$ = "R"
|
|
||||||
220 RETURN
|
|
||||||
230 IF RANDOM < 0.6 THEN 240 ELSE 260
|
|
||||||
240 MYGUESS$ = "S"
|
|
||||||
250 RETURN
|
|
||||||
260 MYGUESS$ = "P"
|
|
||||||
270 RETURN
|
|
||||||
300 REM ROCK
|
|
||||||
310 IF MYGUESS$ = "R" THEN 320 ELSE 340
|
|
||||||
320 PRINT "A draw!"
|
|
||||||
330 RETURN
|
|
||||||
340 IF MYGUESS$ = "S" THEN 350 ELSE 380
|
|
||||||
350 PRINT "I lost!"
|
|
||||||
360 YOURSCORE = YOURSCORE + 1
|
|
||||||
370 RETURN
|
|
||||||
380 IF MYGUESS$ = "P" THEN 390 ELSE 410
|
|
||||||
390 PRINT "I won!"
|
|
||||||
400 MYSCORE = MYSCORE + 1
|
|
||||||
410 RETURN
|
|
||||||
500 REM SCISSORS
|
|
||||||
510 IF MYGUESS$ = "S" THEN 520 ELSE 540
|
|
||||||
520 PRINT "A draw!"
|
|
||||||
530 RETURN
|
|
||||||
540 IF MYGUESS$ = "P" THEN 550 ELSE 580
|
|
||||||
550 PRINT "I lost!"
|
|
||||||
560 YOURSCORE = YOURSCORE + 1
|
|
||||||
570 RETURN
|
|
||||||
580 IF MYGUESS$ = "R" THEN 390 ELSE 410
|
|
||||||
590 PRINT "I won!"
|
|
||||||
600 MYSCORE = MYSCORE + 1
|
|
||||||
610 RETURN
|
|
||||||
700 REM PAPER
|
|
||||||
710 IF MYGUESS$ = "P" THEN 720 ELSE 740
|
|
||||||
720 PRINT "A draw!"
|
|
||||||
730 RETURN
|
|
||||||
740 IF MYGUESS$ = "R" THEN 750 ELSE 780
|
|
||||||
750 PRINT "I lost!"
|
|
||||||
760 YOURSCORE = YOURSCORE + 1
|
|
||||||
770 RETURN
|
|
||||||
780 IF MYGUESS$ = "S" THEN 790 ELSE 810
|
|
||||||
790 PRINT "I won!"
|
|
||||||
800 MYSCORE = MYSCORE + 1
|
|
||||||
810 RETURN
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
2 PRINT TAB ( 34 ) ; "LIFE"
|
|
||||||
4 PRINT TAB ( 15 ) ; "CREATIVE COMPUTING MORRISTOWN NEW JERSEY"
|
|
||||||
6 PRINT : PRINT : PRINT
|
|
||||||
8 PRINT "ENTER YOUR PATTERN, AS A SERIES OF SPACES"
|
|
||||||
9 PRINT "AND STARS, LINE BY LINE. FINISH BY TYPING"
|
|
||||||
10 PRINT "'DONE' ON THE FINAL LINE:"
|
|
||||||
11 X1 = 1 : Y1 = 1 : X2 = 24 : Y2 = 70 : G = 0 : P = 0
|
|
||||||
12 DIM A ( 24 , 70 ) : DIM B$ ( 24 )
|
|
||||||
15 I9 = 1
|
|
||||||
20 C = 1
|
|
||||||
30 INPUT TEMP$
|
|
||||||
35 B$ ( C ) = TEMP$
|
|
||||||
40 IF B$ ( C ) = "DONE" THEN 45 ELSE 50
|
|
||||||
45 B$ ( C ) = "" : GOTO 80
|
|
||||||
46 REM ORIGINAL VERSION REQUIRED USER TO WRITE
|
|
||||||
47 REM DOTS INSTEAD OF SPACES, WHICH WOULD THEN BE
|
|
||||||
48 REM CONVERTED TO SPACES
|
|
||||||
50 REM IF LEFT$(B$(C), 1)="." THEN 55 ELSE 60
|
|
||||||
55 REM B$(C)=" "+RIGHT$(B$(C), LEN(B$(C))-1)
|
|
||||||
60 C = C + 1
|
|
||||||
70 GOTO 30
|
|
||||||
80 C = C - 1 : L = 0
|
|
||||||
90 FOR X = 1 TO C - 1
|
|
||||||
100 IF LEN ( B$ ( X ) ) > L THEN 105 ELSE 110
|
|
||||||
105 L = LEN ( B$ ( X ) )
|
|
||||||
110 NEXT X
|
|
||||||
120 X1 = INT ( 11 - C / 2 )
|
|
||||||
130 Y1 = INT ( 33 - L / 2 )
|
|
||||||
135 REM TRANSCRIBE INPUT PATTERN INTO ARRAY
|
|
||||||
140 FOR X = 1 TO C
|
|
||||||
150 FOR Y = 1 TO LEN ( B$ ( X ) )
|
|
||||||
160 IF MID$ ( B$ ( X ) , Y , 1 ) <> " " THEN 165 ELSE 170
|
|
||||||
165 A ( X1 + X , Y1 + Y ) = 1 : P = P + 1
|
|
||||||
170 NEXT Y
|
|
||||||
180 NEXT X
|
|
||||||
200 PRINT CHR$ ( 27 ) + "[2J"
|
|
||||||
210 PRINT CHR$ ( 27 ) + "[2;1HGENERATION: " ; G ; " POPULATION: " ; P ; CHR$ ( 27 ) + "[K" ;
|
|
||||||
212 IF I9 = 0 THEN 213 ELSE 215
|
|
||||||
213 PRINT " INVALID!" ; CHR$ ( 27 ) + "[K" ;
|
|
||||||
215 X3 = 24 : Y3 = 70 : X4 = 1 : Y4 = 1 : P = 0
|
|
||||||
220 G = G + 1
|
|
||||||
230 FOR X = X1 TO X2
|
|
||||||
240 IF X-X1+1 < 17 THEN PRINT CHR$ ( 27 ) + "[K"
|
|
||||||
250 FOR Y = Y1 TO Y2
|
|
||||||
253 IF A ( X , Y ) = 2 THEN 254 ELSE 256
|
|
||||||
254 A ( X , Y ) = 0 : GOTO 270
|
|
||||||
256 IF A ( X , Y ) = 3 THEN 258 ELSE 260
|
|
||||||
258 A ( X , Y ) = 1 : GOTO 261
|
|
||||||
260 IF A ( X , Y ) <> 1 THEN 270
|
|
||||||
261 IF X-X1+1 < 17 THEN PRINT TAB ( Y ) ; "*" ;
|
|
||||||
262 IF X < X3 THEN 263 ELSE 264
|
|
||||||
263 X3 = X
|
|
||||||
264 IF X > X4 THEN 265 ELSE 266
|
|
||||||
265 X4 = X
|
|
||||||
266 IF Y < Y3 THEN 267 ELSE 268
|
|
||||||
267 Y3 = Y
|
|
||||||
268 IF Y > Y4 THEN 269 ELSE 270
|
|
||||||
269 Y4 = Y
|
|
||||||
270 NEXT Y
|
|
||||||
290 NEXT X
|
|
||||||
293 PRINT
|
|
||||||
295 FOR X = X2 + 1 TO 24
|
|
||||||
296 IF X-X1+1 < 17 THEN PRINT " "*71
|
|
||||||
297 NEXT X
|
|
||||||
299 X1 = X3 : X2 = X4 : Y1 = Y3 : Y2 = Y4
|
|
||||||
301 IF X1 < 3 THEN 302 ELSE 303
|
|
||||||
302 X1 = 3 : I9 = - 1
|
|
||||||
303 IF X2 > 22 THEN 304 ELSE 305
|
|
||||||
304 X2 = 22 : I9 = - 1
|
|
||||||
305 IF Y1 < 3 THEN 306 ELSE 307
|
|
||||||
306 Y1 = 3 : I9 = - 1
|
|
||||||
307 IF Y2 > 68 THEN 308 ELSE 309
|
|
||||||
308 Y2 = 68 : I9 = - 1
|
|
||||||
309 P = 0
|
|
||||||
500 FOR X = X1 - 1 TO X2 + 1
|
|
||||||
510 FOR Y = Y1 - 1 TO Y2 + 1
|
|
||||||
520 C = 0
|
|
||||||
530 FOR I = X - 1 TO X + 1
|
|
||||||
540 FOR J = Y - 1 TO Y + 1
|
|
||||||
550 IF A ( I , J ) = 1 OR A ( I , J ) = 2 THEN 555 ELSE 560
|
|
||||||
555 C = C + 1
|
|
||||||
560 NEXT J
|
|
||||||
570 NEXT I
|
|
||||||
580 IF A ( X , Y ) = 0 THEN 610
|
|
||||||
590 IF C < 3 OR C > 4 THEN 592 ELSE 595
|
|
||||||
592 A ( X , Y ) = 2 : GOTO 600
|
|
||||||
595 P = P + 1
|
|
||||||
600 GOTO 620
|
|
||||||
610 IF C = 3 THEN 615 ELSE 620
|
|
||||||
615 A ( X , Y ) = 3 : P = P + 1
|
|
||||||
620 NEXT Y
|
|
||||||
630 NEXT X
|
|
||||||
635 X1 = X1 - 1 : Y1 = Y1 - 1 : X2 = X2 + 1 : Y2 = Y2 + 1
|
|
||||||
640 GOTO 210
|
|
||||||
650 END
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
#! /usr/bin/python
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
"""This class defines an object that can be returned by the BASICParser to
|
|
||||||
indicate the need for a control flow branch. The information within the
|
|
||||||
object tells the Program the nature of the jump and therefore whether a
|
|
||||||
return address need to be added to the return stack.
|
|
||||||
|
|
||||||
>>> flowsignal = FlowSignal(ftype=FlowSignal.RETURN)
|
|
||||||
>>> print(flowsignal.ftarget)
|
|
||||||
-1
|
|
||||||
>>> flowsignal = FlowSignal(ftarget=100, ftype=FlowSignal.SIMPLE_JUMP)
|
|
||||||
>>> print(flowsignal.ftarget)
|
|
||||||
100
|
|
||||||
>>> print(flowsignal.ftype)
|
|
||||||
0
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class FlowSignal:
|
|
||||||
|
|
||||||
# Jump categories
|
|
||||||
|
|
||||||
# Indicates a simple jump as the result
|
|
||||||
# of a GOTO or conditional branch. The
|
|
||||||
# ftarget value should be the jump target, i.e.
|
|
||||||
# the line number being jumped to
|
|
||||||
SIMPLE_JUMP = 0
|
|
||||||
|
|
||||||
# Indicates a subroutine call where the
|
|
||||||
# return address must be the line number of the instruction
|
|
||||||
# of the following the call.
|
|
||||||
# The ftarget value should be the line number of the first line
|
|
||||||
# of the subroutine
|
|
||||||
GOSUB = 1
|
|
||||||
|
|
||||||
# Indicates the start of a FOR loop where loop
|
|
||||||
# variable has not reached the end value, and therefore the loop
|
|
||||||
# must be repeated. There should be therefore be
|
|
||||||
# no ftarget value associated with it
|
|
||||||
LOOP_BEGIN = 2
|
|
||||||
|
|
||||||
# An indication from a processed NEXT statement that the loop is to
|
|
||||||
# be repeated. Since the return address is already on the stack,
|
|
||||||
# there does not need to be an ftarget value associated with the signal.
|
|
||||||
LOOP_REPEAT = 3
|
|
||||||
|
|
||||||
# An indication from a FOR statement that the loop should be skipped because
|
|
||||||
# loop variable has reached its end value. The ftarget should be
|
|
||||||
# the loop variable to look for in the terminating NEXT statement
|
|
||||||
LOOP_SKIP = 4
|
|
||||||
|
|
||||||
# Indicates a subroutine return has been processed, where the return
|
|
||||||
# address is on the return stack. There should be therefore
|
|
||||||
# be no ftarget value specified
|
|
||||||
RETURN = 5
|
|
||||||
|
|
||||||
# Indicates that execution should cease because a stop statement has
|
|
||||||
# been processed. There should be therefore be no ftarget value specified
|
|
||||||
STOP = 6
|
|
||||||
|
|
||||||
# Indicates that a conditional result block should be executed
|
|
||||||
EXECUTE = 7
|
|
||||||
|
|
||||||
def __init__(self, ftarget=None, ftype=SIMPLE_JUMP, floop_var=None):
|
|
||||||
"""Creates a new FlowSignal for a branch. If the jump
|
|
||||||
target is supplied, then the branch is assumed to be
|
|
||||||
either a GOTO or conditional branch and the type is assigned as
|
|
||||||
SIMPLE_JUMP. If no jump_target is supplied, then a jump_type must be
|
|
||||||
supplied, which must either be GOSUB, RETURN, LOOP_BEGIN,
|
|
||||||
LOOP_REPEAT, LOOP_SKIP or STOP. In the latter cases
|
|
||||||
the jump target is assigned an arbitrary value of None.
|
|
||||||
|
|
||||||
:param ftarget: The associated value
|
|
||||||
:param ftype: Either GOSUB, SIMPLE_JUMP, RETURN, LOOP_BEGIN,
|
|
||||||
LOOP_SKIP or STOP
|
|
||||||
:param floop_var: The loop variable of a FOR/NEXT loop
|
|
||||||
"""
|
|
||||||
|
|
||||||
if ftype not in [self.GOSUB, self.SIMPLE_JUMP, self.LOOP_BEGIN,
|
|
||||||
self.LOOP_REPEAT, self.RETURN,
|
|
||||||
self.LOOP_SKIP, self.STOP, self.EXECUTE]:
|
|
||||||
raise TypeError("Invalid flow signal type supplied: " + str(ftype))
|
|
||||||
|
|
||||||
if ftarget == None and \
|
|
||||||
ftype in [self.SIMPLE_JUMP, self.GOSUB, self.LOOP_SKIP]:
|
|
||||||
raise TypeError("Invalid jump target supplied for flow signal type: " + str(ftarget))
|
|
||||||
|
|
||||||
if ftarget != None and \
|
|
||||||
ftype in [self.RETURN, self.LOOP_BEGIN, self.LOOP_REPEAT,
|
|
||||||
self.STOP, self.EXECUTE]:
|
|
||||||
raise TypeError("Target wrongly supplied for flow signal " + str(ftype))
|
|
||||||
|
|
||||||
self.ftype = ftype
|
|
||||||
self.ftarget = ftarget
|
|
||||||
self.floop_var = floop_var
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
#! /usr/bin/python
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
"""This class implements a BASIC interpreter that
|
|
||||||
presents a prompt to the user. The user may input
|
|
||||||
program statements, list them and run the program.
|
|
||||||
The program may also be saved to disk and loaded
|
|
||||||
again.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from basictoken import BASICToken as Token
|
|
||||||
from lexer import Lexer
|
|
||||||
from program import Program
|
|
||||||
from sys import stderr
|
|
||||||
from traceback import print_exception
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
banner = (r"""
|
|
||||||
._____________ ___________. ___ ___________ ______
|
|
||||||
| _ .__ \ / ___ _ \ / \ / | / |
|
|
||||||
| |_) | \ \/ / | |_) | / ^ \ | (----`| | | ,----'
|
|
||||||
| ___/ \_ _/ | _ < / /_\ \ \ \ | | | |
|
|
||||||
| | | | | |_) \/ _____ \----) | | | | `----.
|
|
||||||
| _| |__| |___________/ \_________/ |____________|
|
|
||||||
""")
|
|
||||||
|
|
||||||
print(banner)
|
|
||||||
|
|
||||||
lexer = Lexer()
|
|
||||||
program = Program()
|
|
||||||
|
|
||||||
# Continuously accept user input and act on it until
|
|
||||||
# the user enters 'EXIT'
|
|
||||||
while True:
|
|
||||||
|
|
||||||
stmt = input('> ')
|
|
||||||
|
|
||||||
try:
|
|
||||||
tokenlist = lexer.tokenize(stmt)
|
|
||||||
|
|
||||||
# Execute commands directly, otherwise
|
|
||||||
# add program statements to the stored
|
|
||||||
# BASIC program
|
|
||||||
|
|
||||||
if len(tokenlist) > 0:
|
|
||||||
|
|
||||||
# Exit the interpreter
|
|
||||||
if tokenlist[0].category == Token.EXIT:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Add a new program statement, beginning
|
|
||||||
# a line number
|
|
||||||
elif tokenlist[0].category == Token.UNSIGNEDINT\
|
|
||||||
and len(tokenlist) > 1:
|
|
||||||
program.add_stmt(tokenlist)
|
|
||||||
|
|
||||||
# Delete a statement from the program
|
|
||||||
elif tokenlist[0].category == Token.UNSIGNEDINT \
|
|
||||||
and len(tokenlist) == 1:
|
|
||||||
program.delete_statement(int(tokenlist[0].lexeme))
|
|
||||||
|
|
||||||
# Execute the program
|
|
||||||
elif tokenlist[0].category == Token.RUN:
|
|
||||||
try:
|
|
||||||
program.execute()
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("Program terminated")
|
|
||||||
|
|
||||||
# List the program
|
|
||||||
elif tokenlist[0].category == Token.LIST:
|
|
||||||
if len(tokenlist) == 2:
|
|
||||||
program.list(int(tokenlist[1].lexeme),int(tokenlist[1].lexeme))
|
|
||||||
elif len(tokenlist) == 3:
|
|
||||||
# if we have 3 tokens, it might be LIST x y for a range
|
|
||||||
# or LIST -y or list x- for a start to y, or x to end
|
|
||||||
if tokenlist[1].lexeme == "-":
|
|
||||||
program.list(None, int(tokenlist[2].lexeme))
|
|
||||||
elif tokenlist[2].lexeme == "-":
|
|
||||||
program.list(int(tokenlist[1].lexeme), None)
|
|
||||||
else:
|
|
||||||
program.list(int(tokenlist[1].lexeme),int(tokenlist[2].lexeme))
|
|
||||||
elif len(tokenlist) == 4:
|
|
||||||
# if we have 4, assume LIST x-y or some other
|
|
||||||
# delimiter for a range
|
|
||||||
program.list(int(tokenlist[1].lexeme),int(tokenlist[3].lexeme))
|
|
||||||
else:
|
|
||||||
program.list()
|
|
||||||
|
|
||||||
# Save the program to disk
|
|
||||||
elif tokenlist[0].category == Token.SAVE:
|
|
||||||
program.save(tokenlist[1].lexeme)
|
|
||||||
print("Program written to file")
|
|
||||||
|
|
||||||
# Load the program from disk
|
|
||||||
elif tokenlist[0].category == Token.LOAD:
|
|
||||||
program.load(tokenlist[1].lexeme)
|
|
||||||
print("Program read from file")
|
|
||||||
|
|
||||||
# Delete the program from memory
|
|
||||||
elif tokenlist[0].category == Token.NEW:
|
|
||||||
program.delete()
|
|
||||||
|
|
||||||
# Unrecognised input
|
|
||||||
else:
|
|
||||||
print("Unrecognised input", file=stderr)
|
|
||||||
for token in tokenlist:
|
|
||||||
token.print_lexeme()
|
|
||||||
print(flush=True)
|
|
||||||
|
|
||||||
# Trap all exceptions so that interpreter
|
|
||||||
# keeps running
|
|
||||||
except Exception as e:
|
|
||||||
print_exception(e,e, \
|
|
||||||
e.__traceback__ if hasattr(e,'__traceback__') else None)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
#! /usr/bin/python
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
"""This class implements a lexical analyser capable
|
|
||||||
of consuming BASIC statements and commands and returning
|
|
||||||
a corresponding list of tokens.
|
|
||||||
|
|
||||||
>>> lexer = Lexer()
|
|
||||||
>>> tokenlist = lexer.tokenize('100 LET I = 10')
|
|
||||||
>>> tokenlist[0].pretty_print()
|
|
||||||
Column: 0 Category: UNSIGNEDINT Lexeme: 100
|
|
||||||
>>> tokenlist = lexer.tokenize('100 IF I <> 10')
|
|
||||||
>>> tokenlist[3].pretty_print()
|
|
||||||
Column: 9 Category: NOTEQUAL Lexeme: <>
|
|
||||||
>>> tokenlist = lexer.tokenize('100 LET I = 3.45')
|
|
||||||
>>> tokenlist[4].pretty_print()
|
|
||||||
Column: 12 Category: UNSIGNEDFLOAT Lexeme: 3.45
|
|
||||||
>>> tokenlist = lexer.tokenize('100 LET I = "HELLO"')
|
|
||||||
>>> tokenlist[4].pretty_print()
|
|
||||||
Column: 12 Category: STRING Lexeme: HELLO
|
|
||||||
"""
|
|
||||||
|
|
||||||
from basictoken import BASICToken as Token
|
|
||||||
|
|
||||||
|
|
||||||
class Lexer:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
|
|
||||||
self.__column = 0 # Current column number
|
|
||||||
self.__stmt = '' # Statement string being processed
|
|
||||||
|
|
||||||
def tokenize(self, stmt):
|
|
||||||
"""Returns a list of tokens obtained by
|
|
||||||
lexical analysis of the specified
|
|
||||||
statement.
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.__stmt = stmt
|
|
||||||
self.__column = 0
|
|
||||||
|
|
||||||
# Establish a list of tokens to be
|
|
||||||
# derived from the statement
|
|
||||||
tokenlist = []
|
|
||||||
|
|
||||||
# Process every character until we
|
|
||||||
# reach the end of the statement string
|
|
||||||
c = self.__get_next_char()
|
|
||||||
while c != '':
|
|
||||||
|
|
||||||
# Skip any preceding whitespace
|
|
||||||
while c.isspace():
|
|
||||||
c = self.__get_next_char()
|
|
||||||
|
|
||||||
# Construct a token, column count already
|
|
||||||
# incremented
|
|
||||||
token = Token(self.__column - 1, None, '')
|
|
||||||
|
|
||||||
# Process strings
|
|
||||||
if c == '"':
|
|
||||||
token.category = Token.STRING
|
|
||||||
|
|
||||||
# Consume all of the characters
|
|
||||||
# until we reach the terminating
|
|
||||||
# quote. Do not store the quotes
|
|
||||||
# in the lexeme
|
|
||||||
c = self.__get_next_char() # Advance past opening quote
|
|
||||||
|
|
||||||
# We explicitly support empty strings
|
|
||||||
if c == '"':
|
|
||||||
# String is empty, leave lexeme as ''
|
|
||||||
# and advance past terminating quote
|
|
||||||
c = self.__get_next_char()
|
|
||||||
|
|
||||||
else:
|
|
||||||
while True:
|
|
||||||
token.lexeme += c # Append the current char to the lexeme
|
|
||||||
c = self.__get_next_char()
|
|
||||||
|
|
||||||
if c == '':
|
|
||||||
raise SyntaxError("Mismatched quotes")
|
|
||||||
|
|
||||||
if c == '"':
|
|
||||||
c = self.__get_next_char() # Advance past terminating quote
|
|
||||||
break
|
|
||||||
|
|
||||||
# Process numbers
|
|
||||||
elif c.isdigit() or c == '.':
|
|
||||||
token.category = Token.UNSIGNEDINT
|
|
||||||
found_point = False
|
|
||||||
if c == '.':
|
|
||||||
token.category = Token.UNSIGNEDFLOAT
|
|
||||||
found_point = True
|
|
||||||
|
|
||||||
# Consume all of the digits, including any decimal point
|
|
||||||
while True:
|
|
||||||
token.lexeme += c # Append the current char to the lexeme
|
|
||||||
c = self.__get_next_char()
|
|
||||||
|
|
||||||
# Break if next character is not a digit
|
|
||||||
# and this is not the first decimal point
|
|
||||||
if not c.isdigit():
|
|
||||||
if c == '.':
|
|
||||||
if found_point is False:
|
|
||||||
found_point = True
|
|
||||||
token.category = Token.UNSIGNEDFLOAT
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Another decimal point found
|
|
||||||
break
|
|
||||||
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Process keywords and names
|
|
||||||
elif c.isalpha():
|
|
||||||
# Consume all of the letters
|
|
||||||
while True:
|
|
||||||
token.lexeme += c # append the current char to the lexeme
|
|
||||||
c = self.__get_next_char()
|
|
||||||
|
|
||||||
# Break if not a letter or a dollar symbol
|
|
||||||
# (the latter is used for string variable names)
|
|
||||||
if not ((c.isalpha() or c.isdigit()) or c == '_' or c == '$'):
|
|
||||||
break
|
|
||||||
|
|
||||||
# Normalise keywords and names to upper case
|
|
||||||
token.lexeme = token.lexeme.upper()
|
|
||||||
|
|
||||||
# Determine if the lexeme is a variable name or a
|
|
||||||
# reserved word
|
|
||||||
if token.lexeme in Token.keywords:
|
|
||||||
token.category = Token.keywords[token.lexeme]
|
|
||||||
|
|
||||||
else:
|
|
||||||
token.category = Token.NAME
|
|
||||||
|
|
||||||
# Remark Statements - process rest of statement without checks
|
|
||||||
if token.lexeme == "REM":
|
|
||||||
while c!= '':
|
|
||||||
token.lexeme += c # Append the current char to the lexeme
|
|
||||||
c = self.__get_next_char()
|
|
||||||
|
|
||||||
# Process operator symbols
|
|
||||||
elif c in Token.smalltokens:
|
|
||||||
save = c
|
|
||||||
c = self.__get_next_char() # c might be '' (end of stmt)
|
|
||||||
twochar = save + c
|
|
||||||
|
|
||||||
if twochar in Token.smalltokens:
|
|
||||||
token.category = Token.smalltokens[twochar]
|
|
||||||
token.lexeme = twochar
|
|
||||||
c = self.__get_next_char() # Move past end of token
|
|
||||||
|
|
||||||
else:
|
|
||||||
# One char token
|
|
||||||
token.category = Token.smalltokens[save]
|
|
||||||
token.lexeme = save
|
|
||||||
|
|
||||||
# We do not recognise this token
|
|
||||||
elif c != '':
|
|
||||||
raise SyntaxError('Syntax error')
|
|
||||||
|
|
||||||
# Append the new token to the list
|
|
||||||
tokenlist.append(token)
|
|
||||||
|
|
||||||
return tokenlist
|
|
||||||
|
|
||||||
def __get_next_char(self):
|
|
||||||
"""Returns the next character in the
|
|
||||||
statement, unless the last character has already
|
|
||||||
been processed, in which case, the empty string is
|
|
||||||
returned.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self.__column < len(self.__stmt):
|
|
||||||
next_char = self.__stmt[self.__column]
|
|
||||||
self.__column = self.__column + 1
|
|
||||||
|
|
||||||
return next_char
|
|
||||||
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
doctest.testmod()
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"title": "PyBasic",
|
|
||||||
"icon": "PyBasic.bmp"
|
|
||||||
}
|
|
||||||
|
|
@ -1,487 +0,0 @@
|
||||||
#! /usr/bin/python
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
"""Class representing a BASIC program.
|
|
||||||
This is a list of statements, ordered by
|
|
||||||
line number.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from basictoken import BASICToken as Token
|
|
||||||
from basicparser import BASICParser
|
|
||||||
from flowsignal import FlowSignal
|
|
||||||
from lexer import Lexer
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class BASICData:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
# array of line numbers to represent data statements
|
|
||||||
self.__datastmts = {}
|
|
||||||
|
|
||||||
# Data pointer
|
|
||||||
self.__next_data = 0
|
|
||||||
|
|
||||||
|
|
||||||
def delete(self):
|
|
||||||
self.__datastmts.clear()
|
|
||||||
self.__next_data = 0
|
|
||||||
|
|
||||||
def delData(self,line_number):
|
|
||||||
if self.__datastmts.get(line_number) != None:
|
|
||||||
del self.__datastmts[line_number]
|
|
||||||
|
|
||||||
def addData(self,line_number,tokenlist):
|
|
||||||
"""
|
|
||||||
Adds the supplied token list
|
|
||||||
to the program's DATA store. If a token list with the
|
|
||||||
same line number already exists, this is
|
|
||||||
replaced.
|
|
||||||
|
|
||||||
line_number: Basic program line number of DATA statement
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.__datastmts[line_number] = tokenlist
|
|
||||||
|
|
||||||
except TypeError as err:
|
|
||||||
raise TypeError("Invalid line number: " + str(err))
|
|
||||||
|
|
||||||
|
|
||||||
def getTokens(self,line_number):
|
|
||||||
"""
|
|
||||||
returns the tokens from the program DATA statement
|
|
||||||
|
|
||||||
line_number: Basic program line number of DATA statement
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__datastmts.get(line_number)
|
|
||||||
|
|
||||||
def readData(self,read_line_number):
|
|
||||||
|
|
||||||
if len(self.__datastmts) == 0:
|
|
||||||
raise RuntimeError('No DATA statements available to READ ' +
|
|
||||||
'in line ' + str(read_line_number))
|
|
||||||
|
|
||||||
data_values = []
|
|
||||||
|
|
||||||
line_numbers = list(self.__datastmts.keys())
|
|
||||||
line_numbers.sort()
|
|
||||||
|
|
||||||
if self.__next_data == 0:
|
|
||||||
self.__next_data = line_numbers[0]
|
|
||||||
elif line_numbers.index(self.__next_data) < len(line_numbers)-1:
|
|
||||||
self.__next_data = line_numbers[line_numbers.index(self.__next_data)+1]
|
|
||||||
else:
|
|
||||||
raise RuntimeError('No DATA statements available to READ ' +
|
|
||||||
'in line ' + str(read_line_number))
|
|
||||||
|
|
||||||
tokenlist = self.__datastmts[self.__next_data]
|
|
||||||
|
|
||||||
sign = 1
|
|
||||||
for token in tokenlist[1:]:
|
|
||||||
if token.category != Token.COMMA:
|
|
||||||
#data_values.append(token.lexeme)
|
|
||||||
|
|
||||||
if token.category == Token.STRING:
|
|
||||||
data_values.append(token.lexeme)
|
|
||||||
elif token.category == Token.UNSIGNEDINT:
|
|
||||||
data_values.append(sign*int(token.lexeme))
|
|
||||||
elif token.category == Token.UNSIGNEDFLOAT:
|
|
||||||
data_values.append(sign*eval(token.lexeme))
|
|
||||||
elif token.category == Token.MINUS:
|
|
||||||
sign = -1
|
|
||||||
#else:
|
|
||||||
#data_values.append(token.lexeme)
|
|
||||||
else:
|
|
||||||
sign = 1
|
|
||||||
|
|
||||||
|
|
||||||
return data_values
|
|
||||||
|
|
||||||
def restore(self,restoreLineNo):
|
|
||||||
if restoreLineNo == 0 or restoreLineNo in self.__datastmts:
|
|
||||||
|
|
||||||
if restoreLineNo == 0:
|
|
||||||
self.__next_data = restoreLineNo
|
|
||||||
else:
|
|
||||||
|
|
||||||
line_numbers = list(self.__datastmts.keys())
|
|
||||||
line_numbers.sort()
|
|
||||||
|
|
||||||
indexln = line_numbers.index(restoreLineNo)
|
|
||||||
|
|
||||||
if indexln == 0:
|
|
||||||
self.__next_data = 0
|
|
||||||
else:
|
|
||||||
self.__next_data = line_numbers[indexln-1]
|
|
||||||
else:
|
|
||||||
raise RuntimeError('Attempt to RESTORE but no DATA ' +
|
|
||||||
'statement at line ' + str(restoreLineNo))
|
|
||||||
|
|
||||||
|
|
||||||
class Program:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
# Dictionary to represent program
|
|
||||||
# statements, keyed by line number
|
|
||||||
self.__program = {}
|
|
||||||
|
|
||||||
# Program counter
|
|
||||||
self.__next_stmt = 0
|
|
||||||
|
|
||||||
# Initialise return stack for subroutine returns
|
|
||||||
self.__return_stack = []
|
|
||||||
|
|
||||||
# return dictionary for loop returns
|
|
||||||
self.__return_loop = {}
|
|
||||||
|
|
||||||
# Setup DATA object
|
|
||||||
self.__data = BASICData()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
|
|
||||||
program_text = ""
|
|
||||||
line_numbers = self.line_numbers()
|
|
||||||
|
|
||||||
for line_number in line_numbers:
|
|
||||||
program_text += self.str_statement(line_number)
|
|
||||||
|
|
||||||
return program_text
|
|
||||||
|
|
||||||
def str_statement(self, line_number):
|
|
||||||
line_text = str(line_number) + " "
|
|
||||||
|
|
||||||
statement = self.__program[line_number]
|
|
||||||
if statement[0].category == Token.DATA:
|
|
||||||
statement = self.__data.getTokens(line_number)
|
|
||||||
for token in statement:
|
|
||||||
# Add in quotes for strings
|
|
||||||
if token.category == Token.STRING:
|
|
||||||
line_text += '"' + token.lexeme + '" '
|
|
||||||
|
|
||||||
else:
|
|
||||||
line_text += token.lexeme + " "
|
|
||||||
line_text += "\n"
|
|
||||||
return line_text
|
|
||||||
|
|
||||||
def list(self, start_line=None, end_line=None):
|
|
||||||
"""Lists the program"""
|
|
||||||
line_numbers = self.line_numbers()
|
|
||||||
if not start_line:
|
|
||||||
start_line = int(line_numbers[0])
|
|
||||||
|
|
||||||
if not end_line:
|
|
||||||
end_line = int(line_numbers[-1])
|
|
||||||
|
|
||||||
for line_number in line_numbers:
|
|
||||||
if int(line_number) >= start_line and int(line_number) <= end_line:
|
|
||||||
print(self.str_statement(line_number), end="")
|
|
||||||
|
|
||||||
def save(self, file):
|
|
||||||
"""Save the program
|
|
||||||
|
|
||||||
:param file: The name and path of the save file, .bas is
|
|
||||||
appended
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not file.lower().endswith(".bas"):
|
|
||||||
file += ".bas"
|
|
||||||
try:
|
|
||||||
with open(file, "w") as outfile:
|
|
||||||
outfile.write(str(self))
|
|
||||||
except OSError:
|
|
||||||
raise OSError("Could not save to file")
|
|
||||||
|
|
||||||
def load(self, file):
|
|
||||||
"""Load the program
|
|
||||||
|
|
||||||
:param file: The name and path of the file to be loaded, .bas is
|
|
||||||
appended
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# New out the program
|
|
||||||
self.delete()
|
|
||||||
if not file.lower().endswith(".bas"):
|
|
||||||
file += ".bas"
|
|
||||||
try:
|
|
||||||
lexer = Lexer()
|
|
||||||
with open(file, "r") as infile:
|
|
||||||
for line in infile:
|
|
||||||
line = line.replace("\r", "").replace("\n", "").strip()
|
|
||||||
tokenlist = lexer.tokenize(line)
|
|
||||||
self.add_stmt(tokenlist)
|
|
||||||
|
|
||||||
except OSError:
|
|
||||||
raise OSError("Could not read file")
|
|
||||||
|
|
||||||
if file.rfind('/') == 0:
|
|
||||||
os.chdir("/")
|
|
||||||
elif file.rfind('/') != -1:
|
|
||||||
os.chdir(file[:file.rfind('/')])
|
|
||||||
|
|
||||||
def add_stmt(self, tokenlist):
|
|
||||||
"""
|
|
||||||
Adds the supplied token list
|
|
||||||
to the program. The first token should
|
|
||||||
be the line number. If a token list with the
|
|
||||||
same line number already exists, this is
|
|
||||||
replaced.
|
|
||||||
|
|
||||||
:param tokenlist: List of BTokens representing a
|
|
||||||
numbered program statement
|
|
||||||
|
|
||||||
"""
|
|
||||||
if len(tokenlist) > 0:
|
|
||||||
try:
|
|
||||||
line_number = int(tokenlist[0].lexeme)
|
|
||||||
if tokenlist[1].lexeme == "DATA":
|
|
||||||
self.__data.addData(line_number,tokenlist[1:])
|
|
||||||
self.__program[line_number] = [tokenlist[1],]
|
|
||||||
else:
|
|
||||||
self.__program[line_number] = tokenlist[1:]
|
|
||||||
|
|
||||||
except TypeError as err:
|
|
||||||
raise TypeError("Invalid line number: " +
|
|
||||||
str(err))
|
|
||||||
|
|
||||||
def line_numbers(self):
|
|
||||||
"""Returns a list of all the
|
|
||||||
line numbers for the program,
|
|
||||||
sorted
|
|
||||||
|
|
||||||
:return: A sorted list of
|
|
||||||
program line numbers
|
|
||||||
"""
|
|
||||||
line_numbers = list(self.__program.keys())
|
|
||||||
line_numbers.sort()
|
|
||||||
|
|
||||||
return line_numbers
|
|
||||||
|
|
||||||
def __execute(self, line_number):
|
|
||||||
"""Execute the statement with the
|
|
||||||
specified line number
|
|
||||||
|
|
||||||
:param line_number: The line number
|
|
||||||
|
|
||||||
:return: The FlowSignal to indicate to the program
|
|
||||||
how to branch if necessary, None otherwise
|
|
||||||
|
|
||||||
"""
|
|
||||||
if line_number not in self.__program.keys():
|
|
||||||
raise RuntimeError("Line number " + line_number +
|
|
||||||
" does not exist")
|
|
||||||
|
|
||||||
statement = self.__program[line_number]
|
|
||||||
|
|
||||||
try:
|
|
||||||
return self.__parser.parse(statement, line_number)
|
|
||||||
|
|
||||||
except RuntimeError as err:
|
|
||||||
raise RuntimeError(str(err))
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
"""Execute the program"""
|
|
||||||
|
|
||||||
self.__parser = BASICParser(self.__data)
|
|
||||||
self.__data.restore(0) # reset data pointer
|
|
||||||
|
|
||||||
line_numbers = self.line_numbers()
|
|
||||||
|
|
||||||
if len(line_numbers) > 0:
|
|
||||||
# Set up an index into the ordered list
|
|
||||||
# of line numbers that can be used for
|
|
||||||
# sequential statement execution. The index
|
|
||||||
# will be incremented by one, unless modified by
|
|
||||||
# a jump
|
|
||||||
index = 0
|
|
||||||
self.set_next_line_number(line_numbers[index])
|
|
||||||
|
|
||||||
# Run through the program until the
|
|
||||||
# has line number has been reached
|
|
||||||
while True:
|
|
||||||
flowsignal = self.__execute(self.get_next_line_number())
|
|
||||||
self.__parser.last_flowsignal = flowsignal
|
|
||||||
|
|
||||||
if flowsignal:
|
|
||||||
if flowsignal.ftype == FlowSignal.SIMPLE_JUMP:
|
|
||||||
# GOTO or conditional branch encountered
|
|
||||||
try:
|
|
||||||
index = line_numbers.index(flowsignal.ftarget)
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
raise RuntimeError("Invalid line number supplied in GOTO or conditional branch: "
|
|
||||||
+ str(flowsignal.ftarget))
|
|
||||||
|
|
||||||
self.set_next_line_number(flowsignal.ftarget)
|
|
||||||
|
|
||||||
elif flowsignal.ftype == FlowSignal.GOSUB:
|
|
||||||
# Subroutine call encountered
|
|
||||||
# Add line number of next instruction to
|
|
||||||
# the return stack
|
|
||||||
if index + 1 < len(line_numbers):
|
|
||||||
self.__return_stack.append(line_numbers[index + 1])
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise RuntimeError("GOSUB at end of program, nowhere to return")
|
|
||||||
|
|
||||||
# Set the index to be the subroutine start line
|
|
||||||
# number
|
|
||||||
try:
|
|
||||||
index = line_numbers.index(flowsignal.ftarget)
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
raise RuntimeError("Invalid line number supplied in subroutine call: "
|
|
||||||
+ str(flowsignal.ftarget))
|
|
||||||
|
|
||||||
self.set_next_line_number(flowsignal.ftarget)
|
|
||||||
|
|
||||||
elif flowsignal.ftype == FlowSignal.RETURN:
|
|
||||||
# Subroutine return encountered
|
|
||||||
# Pop return address from the stack
|
|
||||||
try:
|
|
||||||
index = line_numbers.index(self.__return_stack.pop())
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
raise RuntimeError("Invalid subroutine return in line " +
|
|
||||||
str(self.get_next_line_number()))
|
|
||||||
|
|
||||||
except IndexError:
|
|
||||||
raise RuntimeError("RETURN encountered without corresponding " +
|
|
||||||
"subroutine call in line " + str(self.get_next_line_number()))
|
|
||||||
|
|
||||||
self.set_next_line_number(line_numbers[index])
|
|
||||||
|
|
||||||
elif flowsignal.ftype == FlowSignal.STOP:
|
|
||||||
break
|
|
||||||
|
|
||||||
elif flowsignal.ftype == FlowSignal.LOOP_BEGIN:
|
|
||||||
# Loop start encountered
|
|
||||||
# Put loop line number on the stack so
|
|
||||||
# that it can be returned to when the loop
|
|
||||||
# repeats
|
|
||||||
self.__return_loop[flowsignal.floop_var] = line_numbers[index]
|
|
||||||
|
|
||||||
# Continue to the next statement in the loop
|
|
||||||
index = index + 1
|
|
||||||
|
|
||||||
if index < len(line_numbers):
|
|
||||||
self.set_next_line_number(line_numbers[index])
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Reached end of program
|
|
||||||
raise RuntimeError("Program terminated within a loop")
|
|
||||||
|
|
||||||
elif flowsignal.ftype == FlowSignal.LOOP_SKIP:
|
|
||||||
# Loop variable has reached end value, so ignore
|
|
||||||
# all statements within loop and move past the corresponding
|
|
||||||
# NEXT statement
|
|
||||||
index = index + 1
|
|
||||||
while index < len(line_numbers):
|
|
||||||
next_line_number = line_numbers[index]
|
|
||||||
temp_tokenlist = self.__program[next_line_number]
|
|
||||||
|
|
||||||
if temp_tokenlist[0].category == Token.NEXT and \
|
|
||||||
len(temp_tokenlist) > 1:
|
|
||||||
# Check the loop variable to ensure we have not found
|
|
||||||
# the NEXT statement for a nested loop
|
|
||||||
if temp_tokenlist[1].lexeme == flowsignal.ftarget:
|
|
||||||
# Move the statement after this NEXT, if there
|
|
||||||
# is one
|
|
||||||
index = index + 1
|
|
||||||
if index < len(line_numbers):
|
|
||||||
next_line_number = line_numbers[index] # Statement after the NEXT
|
|
||||||
self.set_next_line_number(next_line_number)
|
|
||||||
break
|
|
||||||
|
|
||||||
index = index + 1
|
|
||||||
|
|
||||||
# Check we have not reached end of program
|
|
||||||
if index >= len(line_numbers):
|
|
||||||
# Terminate the program
|
|
||||||
break
|
|
||||||
|
|
||||||
elif flowsignal.ftype == FlowSignal.LOOP_REPEAT:
|
|
||||||
# Loop repeat encountered
|
|
||||||
# Pop the loop start address from the stack
|
|
||||||
try:
|
|
||||||
index = line_numbers.index(self.__return_loop.pop(flowsignal.floop_var))
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
raise RuntimeError("Invalid loop exit in line " +
|
|
||||||
str(self.get_next_line_number()))
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
raise RuntimeError("NEXT encountered without corresponding " +
|
|
||||||
"FOR loop in line " + str(self.get_next_line_number()))
|
|
||||||
|
|
||||||
self.set_next_line_number(line_numbers[index])
|
|
||||||
|
|
||||||
else:
|
|
||||||
index = index + 1
|
|
||||||
|
|
||||||
if index < len(line_numbers):
|
|
||||||
self.set_next_line_number(line_numbers[index])
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Reached end of program
|
|
||||||
break
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise RuntimeError("No statements to execute")
|
|
||||||
|
|
||||||
def delete(self):
|
|
||||||
"""Deletes the program by emptying the dictionary"""
|
|
||||||
self.__program.clear()
|
|
||||||
self.__data.delete()
|
|
||||||
|
|
||||||
def delete_statement(self, line_number):
|
|
||||||
"""Deletes a statement from the program with
|
|
||||||
the specified line number, if it exists
|
|
||||||
|
|
||||||
:param line_number: The line number to be deleted
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.__data.delData(line_number)
|
|
||||||
try:
|
|
||||||
del self.__program[line_number]
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
raise KeyError("Line number does not exist")
|
|
||||||
|
|
||||||
def get_next_line_number(self):
|
|
||||||
"""Returns the line number of the next statement
|
|
||||||
to be executed
|
|
||||||
|
|
||||||
:return: The line number
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__next_stmt
|
|
||||||
|
|
||||||
def set_next_line_number(self, line_number):
|
|
||||||
"""Sets the line number of the next
|
|
||||||
statement to be executed
|
|
||||||
|
|
||||||
:param line_number: The new line number
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.__next_stmt = line_number
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.1 KiB |
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +0,0 @@
|
||||||
# Launches the PyDOS shell
|
|
||||||
#
|
|
||||||
# This is done in a sperate file so that __name__ is set to "PyDOS" instead of "__main__"
|
|
||||||
# which helps some modules detect that they are running in PyDOS.
|
|
||||||
|
|
||||||
import PyDOS
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"title": "PyDOS",
|
|
||||||
"icon": "PyDOS.bmp"
|
|
||||||
}
|
|
||||||
|
|
@ -15,7 +15,7 @@ from . import util
|
||||||
from adafruit_pathlib import Path
|
from adafruit_pathlib import Path
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
from adafruit_argv_file import argv_filename
|
from argv_file_helper import argv_filename
|
||||||
|
|
||||||
# pylint: disable=redefined-builtin
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
|
|
@ -24,6 +24,7 @@ from adafruit_argv_file import argv_filename
|
||||||
|
|
||||||
INPUT_DISPLAY_REFRESH_COOLDOWN = 0.3 # s
|
INPUT_DISPLAY_REFRESH_COOLDOWN = 0.3 # s
|
||||||
SHOW_MEMFREE = False
|
SHOW_MEMFREE = False
|
||||||
|
TAB_SIZE = 4 # Number of spaces to represent a tab
|
||||||
|
|
||||||
|
|
||||||
class MaybeDisableReload:
|
class MaybeDisableReload:
|
||||||
|
|
@ -79,34 +80,83 @@ class Buffer:
|
||||||
return len(self) - 1
|
return len(self) - 1
|
||||||
|
|
||||||
def insert(self, cursor, string):
|
def insert(self, cursor, string):
|
||||||
row, col = cursor.row, cursor.col
|
row, visual_col = cursor.row, cursor.col
|
||||||
# print(f"len: {len(self.lines)}")
|
actual_col = self._visual_to_actual_col(row, visual_col)
|
||||||
# print(f"row: {row}")
|
|
||||||
try:
|
try:
|
||||||
current = self.lines.pop(row)
|
current = self.lines.pop(row)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
current = ""
|
current = ""
|
||||||
new = current[:col] + string + current[col:]
|
|
||||||
|
new = current[:actual_col] + string + current[actual_col:]
|
||||||
self.lines.insert(row, new)
|
self.lines.insert(row, new)
|
||||||
|
|
||||||
def split(self, cursor):
|
def split(self, cursor):
|
||||||
row, col = cursor.row, cursor.col
|
row, visual_col = cursor.row, cursor.col
|
||||||
|
actual_col = self._visual_to_actual_col(row, visual_col)
|
||||||
|
|
||||||
current = self.lines.pop(row)
|
current = self.lines.pop(row)
|
||||||
self.lines.insert(row, current[:col])
|
self.lines.insert(row, current[:actual_col])
|
||||||
self.lines.insert(row + 1, current[col:])
|
self.lines.insert(row + 1, current[actual_col:])
|
||||||
|
|
||||||
def delete(self, cursor):
|
def delete(self, cursor):
|
||||||
row, col = cursor.row, cursor.col
|
row, visual_col = cursor.row, cursor.col
|
||||||
if (row, col) < (self.bottom, len(self[row])):
|
actual_col = self._visual_to_actual_col(row, visual_col)
|
||||||
|
|
||||||
|
if (row, actual_col) < (self.bottom, len(self[row])):
|
||||||
current = self.lines.pop(row)
|
current = self.lines.pop(row)
|
||||||
if col < len(current):
|
if actual_col < len(current):
|
||||||
new = current[:col] + current[col + 1:]
|
new = current[:actual_col] + current[actual_col + 1:]
|
||||||
self.lines.insert(row, new)
|
self.lines.insert(row, new)
|
||||||
else:
|
else:
|
||||||
nextline = self.lines.pop(row)
|
nextline = self.lines.pop(row)
|
||||||
new = current + nextline
|
new = current + nextline
|
||||||
self.lines.insert(row, new)
|
self.lines.insert(row, new)
|
||||||
|
|
||||||
|
def _visual_to_actual_col(self, row, visual_col):
|
||||||
|
"""Convert a visual column position to the actual buffer position"""
|
||||||
|
if row >= len(self.lines):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
line = self.lines[row]
|
||||||
|
actual_col = 0
|
||||||
|
current_visual_col = 0
|
||||||
|
|
||||||
|
while current_visual_col < visual_col and actual_col < len(line):
|
||||||
|
if line[actual_col] == '\t':
|
||||||
|
current_visual_col += TAB_SIZE
|
||||||
|
else:
|
||||||
|
current_visual_col += 1
|
||||||
|
|
||||||
|
if current_visual_col <= visual_col:
|
||||||
|
actual_col += 1
|
||||||
|
|
||||||
|
return actual_col
|
||||||
|
|
||||||
|
def actual_to_visual_col(self, row, actual_col):
|
||||||
|
"""Convert an actual buffer position to visual column position"""
|
||||||
|
if row >= len(self.lines) or actual_col > len(self.lines[row]):
|
||||||
|
return actual_col
|
||||||
|
|
||||||
|
line = self.lines[row]
|
||||||
|
visual_col = 0
|
||||||
|
|
||||||
|
for i in range(actual_col):
|
||||||
|
if i < len(line) and line[i] == '\t':
|
||||||
|
visual_col += TAB_SIZE
|
||||||
|
else:
|
||||||
|
visual_col += 1
|
||||||
|
|
||||||
|
return visual_col
|
||||||
|
|
||||||
|
def get_visual_length(self, row):
|
||||||
|
"""Get the visual length of a line, accounting for tabs"""
|
||||||
|
if row >= len(self.lines):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
line = self.lines[row]
|
||||||
|
return sum(TAB_SIZE if c == '\t' else 1 for c in line)
|
||||||
|
|
||||||
|
|
||||||
def clamp(x, lower, upper):
|
def clamp(x, lower, upper):
|
||||||
if x < lower:
|
if x < lower:
|
||||||
|
|
@ -142,42 +192,48 @@ class Cursor:
|
||||||
self._col_hint = col
|
self._col_hint = col
|
||||||
|
|
||||||
def _clamp_col(self, buffer):
|
def _clamp_col(self, buffer):
|
||||||
self._col = min(self._col_hint, len(buffer[self.row]))
|
visual_length = buffer.get_visual_length(self.row)
|
||||||
|
self._col = min(self._col_hint, visual_length)
|
||||||
|
|
||||||
def up(self, buffer): # pylint: disable=invalid-name
|
def up(self, buffer):
|
||||||
if self.row > 0:
|
if self.row > 0:
|
||||||
self.row -= 1
|
self.row -= 1
|
||||||
self._clamp_col(buffer)
|
self._clamp_col(buffer)
|
||||||
# print(f"cursor pos: {self.row}, {self.col}")
|
|
||||||
|
|
||||||
def down(self, buffer):
|
def down(self, buffer):
|
||||||
if self.row < len(buffer) - 1:
|
if self.row < len(buffer) - 1:
|
||||||
self.row += 1
|
self.row += 1
|
||||||
self._clamp_col(buffer)
|
self._clamp_col(buffer)
|
||||||
# print(f"cursor pos: {self.row}, {self.col}")
|
|
||||||
|
|
||||||
def left(self, buffer):
|
def left(self, buffer):
|
||||||
if self.col > 0:
|
if self.col > 0:
|
||||||
self.col -= 1
|
# Check if cursor is at the end of a tab
|
||||||
# print(f"cursor pos: {self.row}, {self.col}")
|
actual_col = buffer._visual_to_actual_col(self.row, self.col)
|
||||||
|
if actual_col > 0 and buffer[self.row][actual_col - 1] == '\t':
|
||||||
|
# If we're at a tab character, move visual position back by TAB_SIZE
|
||||||
|
self.col = buffer.actual_to_visual_col(self.row, actual_col - 1)
|
||||||
|
else:
|
||||||
|
self.col -= 1
|
||||||
elif self.row > 0:
|
elif self.row > 0:
|
||||||
self.row -= 1
|
self.row -= 1
|
||||||
self.col = len(buffer[self.row])
|
self.col = buffer.get_visual_length(self.row)
|
||||||
# print(f"cursor pos: {self.row}, {self.col}")
|
|
||||||
|
|
||||||
def right(self, buffer):
|
def right(self, buffer):
|
||||||
# print(f"len: {len(buffer)}")
|
visual_length = buffer.get_visual_length(self.row)
|
||||||
if len(buffer) > 0 and self.col < len(buffer[self.row]):
|
if self.col < visual_length:
|
||||||
self.col += 1
|
# Check if we're on a tab character
|
||||||
# print(f"cursor pos: {self.row}, {self.col}")
|
actual_col = buffer._visual_to_actual_col(self.row, self.col)
|
||||||
|
if actual_col < len(buffer[self.row]) and buffer[self.row][actual_col] == '\t':
|
||||||
|
# If we're on a tab character, move visual position forward by TAB_SIZE
|
||||||
|
self.col = buffer.actual_to_visual_col(self.row, actual_col + 1)
|
||||||
|
else:
|
||||||
|
self.col += 1
|
||||||
elif self.row < len(buffer) - 1:
|
elif self.row < len(buffer) - 1:
|
||||||
self.row += 1
|
self.row += 1
|
||||||
self.col = 0
|
self.col = 0
|
||||||
# print(f"cursor pos: {self.row}, {self.col}")
|
|
||||||
|
|
||||||
def end(self, buffer):
|
def end(self, buffer):
|
||||||
self.col = len(buffer[self.row])
|
self.col = buffer.get_visual_length(self.row)
|
||||||
# print(f"cursor pos: {self.row}, {self.col}")
|
|
||||||
|
|
||||||
|
|
||||||
class Window:
|
class Window:
|
||||||
|
|
@ -191,7 +247,7 @@ class Window:
|
||||||
def bottom(self):
|
def bottom(self):
|
||||||
return self.row + self.n_rows - 1
|
return self.row + self.n_rows - 1
|
||||||
|
|
||||||
def up(self, cursor): # pylint: disable=invalid-name
|
def up(self, cursor):
|
||||||
if cursor.row == self.row - 1 and self.row > 0:
|
if cursor.row == self.row - 1 and self.row > 0:
|
||||||
self.row -= 1
|
self.row -= 1
|
||||||
|
|
||||||
|
|
@ -219,7 +275,7 @@ def right(window, buffer, cursor):
|
||||||
window.horizontal_scroll(cursor)
|
window.horizontal_scroll(cursor)
|
||||||
|
|
||||||
|
|
||||||
def home(window, buffer, cursor): # pylint: disable=unused-argument
|
def home(window, buffer, cursor):
|
||||||
cursor.col = 0
|
cursor.col = 0
|
||||||
window.horizontal_scroll(cursor)
|
window.horizontal_scroll(cursor)
|
||||||
|
|
||||||
|
|
@ -229,22 +285,60 @@ def end(window, buffer, cursor):
|
||||||
window.horizontal_scroll(cursor)
|
window.horizontal_scroll(cursor)
|
||||||
|
|
||||||
|
|
||||||
def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: disable=too-many-branches,too-many-statements
|
def is_at_tab(buffer, row, col):
|
||||||
|
"""Check if a visual position corresponds to a tab character"""
|
||||||
|
if row >= len(buffer.lines):
|
||||||
|
return False
|
||||||
|
|
||||||
def _only_spaces_before(cursor):
|
actual_col = buffer._visual_to_actual_col(row, col)
|
||||||
i = cursor.col - 1
|
if actual_col >= len(buffer.lines[row]):
|
||||||
while i >= 0:
|
return False
|
||||||
print(f"i: {i} chr: '{buffer.lines[cursor.row][i]}'")
|
|
||||||
if buffer.lines[cursor.row][i] != " ":
|
return buffer.lines[row][actual_col] == '\t'
|
||||||
return False
|
|
||||||
i -= 1
|
|
||||||
return True
|
def get_tab_visual_positions(buffer, row, col):
|
||||||
|
"""Get all visual positions that belong to a tab at the current position"""
|
||||||
|
if not is_at_tab(buffer, row, col):
|
||||||
|
return []
|
||||||
|
|
||||||
|
actual_col = buffer._visual_to_actual_col(row, col)
|
||||||
|
visual_start = buffer.actual_to_visual_col(row, actual_col)
|
||||||
|
|
||||||
|
return list(range(visual_start, visual_start + TAB_SIZE))
|
||||||
|
|
||||||
|
|
||||||
|
def is_within_tab_range(buffer, row, col):
|
||||||
|
"""Check if a visual position is within any tab's visual range"""
|
||||||
|
if row >= len(buffer.lines):
|
||||||
|
return False
|
||||||
|
|
||||||
|
line = buffer.lines[row]
|
||||||
|
for i, char in enumerate(line):
|
||||||
|
if char == '\t':
|
||||||
|
visual_start = buffer.actual_to_visual_col(row, i)
|
||||||
|
visual_end = visual_start + TAB_SIZE
|
||||||
|
if visual_start <= col < visual_end:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def only_spaces_before(buffer, cursor):
|
||||||
|
"""Check if there are only spaces before the cursor"""
|
||||||
|
actual_col = buffer._visual_to_actual_col(cursor.row, cursor.col)
|
||||||
|
for i in range(actual_col):
|
||||||
|
if buffer.lines[cursor.row][i] != " ":
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def editor(stdscr, filename, mouse=None, terminal_tilegrid=None):
|
||||||
if os_exists(filename):
|
if os_exists(filename):
|
||||||
with open(filename, "r", encoding="utf-8") as f:
|
with open(filename, "r", encoding="utf-8") as f:
|
||||||
buffer = Buffer(f.read().splitlines())
|
buffer = Buffer(f.read().splitlines())
|
||||||
else:
|
else:
|
||||||
buffer = Buffer([""])
|
buffer = Buffer([""])
|
||||||
print(f"cwd: {os.getcwd()} | {os.getcwd() == "/apps/editor"}")
|
|
||||||
if os.getcwd() != "/apps/editor" and os.getcwd() != "/":
|
if os.getcwd() != "/apps/editor" and os.getcwd() != "/":
|
||||||
absolute_filepath = os.getcwd() + "/" + filename
|
absolute_filepath = os.getcwd() + "/" + filename
|
||||||
else:
|
else:
|
||||||
|
|
@ -252,23 +346,15 @@ def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: dis
|
||||||
|
|
||||||
user_message = None
|
user_message = None
|
||||||
user_message_shown_time = -1
|
user_message_shown_time = -1
|
||||||
user_prompt = None
|
|
||||||
user_response = ""
|
|
||||||
last_find = ""
|
|
||||||
find_command = False
|
|
||||||
goto_command = False
|
|
||||||
|
|
||||||
clicked_tile_coords = [None, None]
|
clicked_tile_coords = [None, None]
|
||||||
|
|
||||||
window = Window(curses.LINES - 1, curses.COLS - 1)
|
window = Window(curses.LINES - 1, curses.COLS - 1)
|
||||||
cursor = Cursor()
|
cursor = Cursor()
|
||||||
terminal_tilegrid.pixel_shader[cursor.col,cursor.row] = [1, 0]
|
|
||||||
|
# Initialize cursor highlighting
|
||||||
|
highlight_cursor_position(terminal_tilegrid, buffer, cursor)
|
||||||
old_cursor_pos = (cursor.col, cursor.row)
|
old_cursor_pos = (cursor.col, cursor.row)
|
||||||
old_window_pos = (window.col, window.row)
|
|
||||||
# try:
|
|
||||||
# visible_cursor.text = buffer[0][0]
|
|
||||||
# except IndexError:
|
|
||||||
# visible_cursor.text = " "
|
|
||||||
|
|
||||||
stdscr.erase()
|
stdscr.erase()
|
||||||
|
|
||||||
|
|
@ -278,107 +364,67 @@ def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: dis
|
||||||
if img[row] == line:
|
if img[row] == line:
|
||||||
return
|
return
|
||||||
img[row] = line
|
img[row] = line
|
||||||
line += " " * (window.n_cols - len(line))
|
# Calculate displayed length for padding
|
||||||
|
visual_length = sum(TAB_SIZE if c == '\t' else 1 for c in line)
|
||||||
|
padding = window.n_cols - visual_length
|
||||||
|
if padding > 0:
|
||||||
|
line += " " * padding
|
||||||
stdscr.addstr(row, 0, line)
|
stdscr.addstr(row, 0, line)
|
||||||
|
|
||||||
print(f"cwd: {os.getcwd()} | abs path: {absolute_filepath} | filename: {filename}")
|
|
||||||
while True:
|
while True:
|
||||||
lastrow = 0
|
lastrow = 0
|
||||||
for row, line in enumerate(buffer[window.row: window.row + window.n_rows]):
|
for row, line in enumerate(buffer[window.row: window.row + window.n_rows]):
|
||||||
lastrow = row
|
lastrow = row
|
||||||
|
|
||||||
if row == cursor.row - window.row and window.col > 0:
|
if row == cursor.row - window.row and window.col > 0:
|
||||||
line = "«" + line[window.col + 1:]
|
line = "«" + line[window.col + 1:]
|
||||||
if len(line) > window.n_cols:
|
|
||||||
line = line[: window.n_cols - 1] + "»"
|
# Calculate visual length for line truncation
|
||||||
|
visual_length = sum(TAB_SIZE if c == '\t' else 1 for c in line)
|
||||||
|
if visual_length > window.n_cols:
|
||||||
|
# Find the position to truncate based on visual length
|
||||||
|
actual_col = 0
|
||||||
|
current_visual_col = 0
|
||||||
|
while current_visual_col < window.n_cols - 1 and actual_col < len(line):
|
||||||
|
if line[actual_col] == '\t':
|
||||||
|
current_visual_col += TAB_SIZE
|
||||||
|
else:
|
||||||
|
current_visual_col += 1
|
||||||
|
actual_col += 1
|
||||||
|
|
||||||
|
if actual_col < len(line):
|
||||||
|
line = line[:actual_col] + "»"
|
||||||
|
|
||||||
setline(row, line)
|
setline(row, line)
|
||||||
|
|
||||||
for row in range(lastrow + 1, window.n_rows):
|
for row in range(lastrow + 1, window.n_rows):
|
||||||
setline(row, "~~ EOF ~~")
|
setline(row, "~~ EOF ~~")
|
||||||
row = curses.LINES - 1
|
row = curses.LINES - 1
|
||||||
|
|
||||||
if user_message is None and user_prompt is None:
|
if user_message is None:
|
||||||
if (not absolute_filepath.startswith("/saves/") and
|
if (not absolute_filepath.startswith("/saves/") and
|
||||||
not absolute_filepath.startswith("/sd/") and
|
not absolute_filepath.startswith("/sd/") and
|
||||||
util.readonly()):
|
util.readonly()):
|
||||||
|
|
||||||
line = f"{absolute_filepath:12} (mnt RO ^W) | ^R Run | ^O Open | ^F Find | ^G GoTo | ^C quit {gc_mem_free_hint()}"
|
line = f"{absolute_filepath:12} (mnt RO ^W) | ^R run | ^O Open | ^C: quit{gc_mem_free_hint()}"
|
||||||
else:
|
else:
|
||||||
line = f"{absolute_filepath:12} (mnt RW ^W) | ^R Run | ^O Open | ^F Find | ^G GoTo | ^S Save | ^X save & eXit | ^C quit {gc_mem_free_hint()}"
|
line = f"{absolute_filepath:12} (mnt RW ^W) | ^R run | ^O Open | ^S save | ^X: save & exit | ^C: exit no save{gc_mem_free_hint()}"
|
||||||
line = line + " " * (window.n_cols - len(line))
|
else:
|
||||||
line = line[:window.n_cols-len(f'{cursor.row+1},{cursor.col+1}')] + f"{cursor.row+1},{cursor.col+1}"
|
|
||||||
|
|
||||||
elif user_message is not None:
|
|
||||||
line = user_message
|
line = user_message
|
||||||
if user_message_shown_time + 3.0 < time.monotonic():
|
if user_message_shown_time + 3.0 < time.monotonic():
|
||||||
user_message = None
|
user_message = None
|
||||||
elif user_prompt is not None:
|
|
||||||
line = f'{user_prompt} {user_response}'
|
|
||||||
setline(row, line)
|
setline(row, line)
|
||||||
|
|
||||||
stdscr.move(*window.translate(cursor))
|
stdscr.move(*window.translate(cursor))
|
||||||
|
|
||||||
# display.refresh(minimum_frames_per_second=20)
|
|
||||||
k = stdscr.getkey()
|
k = stdscr.getkey()
|
||||||
if k is not None:
|
if k is not None:
|
||||||
# print(repr(k))
|
if len(k) == 1 and " " <= k <= "~":
|
||||||
if user_prompt is not None:
|
|
||||||
if len(k) == 1 and " " <= k <= "~":
|
|
||||||
user_response += k
|
|
||||||
elif k == "\n":
|
|
||||||
user_prompt = None
|
|
||||||
|
|
||||||
if find_command:
|
|
||||||
found = False
|
|
||||||
if user_response == "":
|
|
||||||
user_response = last_find
|
|
||||||
if user_response:
|
|
||||||
last_find = user_response
|
|
||||||
if buffer[cursor.row][min(cursor.col+1,len(buffer[cursor.row])-1):].find(user_response) != -1:
|
|
||||||
found = True
|
|
||||||
user_message = f"Found '{user_response}' in line {cursor.row+1}"
|
|
||||||
cursor.col += buffer[cursor.row][cursor.col:].find(user_response) - 1
|
|
||||||
right(window, buffer, cursor)
|
|
||||||
else:
|
|
||||||
for r, line in enumerate(buffer[cursor.row+1:]):
|
|
||||||
if line.find(user_response) != -1:
|
|
||||||
found = True
|
|
||||||
user_message = f"Found '{user_response}' in line {r + cursor.row + 2}"
|
|
||||||
cursor.row = clamp(r + cursor.row + 1, 0, len(buffer) - 1)
|
|
||||||
window.row = clamp(cursor.row - window.n_rows // 2, 0, len(buffer) - window.n_rows)
|
|
||||||
cursor.col = line.find(user_response) - 1
|
|
||||||
right(window, buffer, cursor)
|
|
||||||
break
|
|
||||||
|
|
||||||
if not found:
|
|
||||||
user_message = f"'{user_response}' not found"
|
|
||||||
user_message_shown_time = time.monotonic()
|
|
||||||
|
|
||||||
user_response = ""
|
|
||||||
find_command = False
|
|
||||||
|
|
||||||
elif goto_command:
|
|
||||||
if user_response.isdigit():
|
|
||||||
cursor.row = clamp(int(user_response) - 1, 0, len(buffer) - 1)
|
|
||||||
window.row = clamp(cursor.row - window.n_rows // 2, 0, len(buffer) - window.n_rows)
|
|
||||||
cursor.col = 0
|
|
||||||
window.horizontal_scroll(cursor)
|
|
||||||
|
|
||||||
user_response = ""
|
|
||||||
goto_command = False
|
|
||||||
|
|
||||||
elif k == "\x7f" or k == "\x08": # backspace
|
|
||||||
user_response = user_response[:-1]
|
|
||||||
elif k == "\x1b": # escape
|
|
||||||
user_prompt = None
|
|
||||||
user_response = ""
|
|
||||||
else:
|
|
||||||
print(f"unhandled k: {k}")
|
|
||||||
print(f"unhandled K: {ord(k)}")
|
|
||||||
print(f"unhandled k: {bytes(k, 'utf-8')}")
|
|
||||||
|
|
||||||
elif len(k) == 1 and " " <= k <= "~":
|
|
||||||
buffer.insert(cursor, k)
|
buffer.insert(cursor, k)
|
||||||
for _ in k:
|
right(window, buffer, cursor)
|
||||||
right(window, buffer, cursor)
|
elif k == "\t":
|
||||||
|
buffer.insert(cursor, k)
|
||||||
|
right(window, buffer, cursor)
|
||||||
elif k == "\x18": # ctrl-x
|
elif k == "\x18": # ctrl-x
|
||||||
if not util.readonly():
|
if not util.readonly():
|
||||||
with open(filename, "w", encoding="utf-8") as f:
|
with open(filename, "w", encoding="utf-8") as f:
|
||||||
|
|
@ -392,11 +438,6 @@ def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: dis
|
||||||
print(row)
|
print(row)
|
||||||
print("---- end file contents ----")
|
print("---- end file contents ----")
|
||||||
elif k == "\x13": # Ctrl-S
|
elif k == "\x13": # Ctrl-S
|
||||||
print(absolute_filepath)
|
|
||||||
print(f"starts with saves: {absolute_filepath.startswith("/saves/")}")
|
|
||||||
print(f"stars saves: {absolute_filepath.startswith("/saves/")}")
|
|
||||||
print(f"stars sd: {absolute_filepath.startswith("/sd/")}")
|
|
||||||
print(f"readonly: {util.readonly()}")
|
|
||||||
if (absolute_filepath.startswith("/saves/") or
|
if (absolute_filepath.startswith("/saves/") or
|
||||||
absolute_filepath.startswith("/sd/") or
|
absolute_filepath.startswith("/sd/") or
|
||||||
not util.readonly()):
|
not util.readonly()):
|
||||||
|
|
@ -429,31 +470,17 @@ def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: dis
|
||||||
working_directory=Path(filename).parent.absolute())
|
working_directory=Path(filename).parent.absolute())
|
||||||
supervisor.reload()
|
supervisor.reload()
|
||||||
elif k == "\x0f": # Ctrl-O
|
elif k == "\x0f": # Ctrl-O
|
||||||
|
|
||||||
supervisor.set_next_code_file("/apps/editor/code.py", sticky_on_reload=False, reload_on_error=True,
|
supervisor.set_next_code_file("/apps/editor/code.py", sticky_on_reload=False, reload_on_error=True,
|
||||||
working_directory="/apps/editor")
|
working_directory="/apps/editor")
|
||||||
supervisor.reload()
|
supervisor.reload()
|
||||||
elif k == "\x06": # Ctrl-F
|
|
||||||
find_command = True
|
|
||||||
if last_find == "":
|
|
||||||
user_prompt = "Find:"
|
|
||||||
else:
|
|
||||||
user_prompt = f"Find: [{last_find}]"
|
|
||||||
elif k == "\x07": # Ctrl-G
|
|
||||||
goto_command = True
|
|
||||||
user_prompt = "Goto line:"
|
|
||||||
|
|
||||||
elif k == "KEY_HOME":
|
elif k == "KEY_HOME":
|
||||||
home(window, buffer, cursor)
|
home(window, buffer, cursor)
|
||||||
elif k == "KEY_END":
|
elif k == "KEY_END":
|
||||||
end(window, buffer, cursor)
|
end(window, buffer, cursor)
|
||||||
elif k == "KEY_LEFT":
|
|
||||||
left(window, buffer, cursor)
|
|
||||||
elif k == "KEY_DOWN":
|
elif k == "KEY_DOWN":
|
||||||
cursor.down(buffer)
|
cursor.down(buffer)
|
||||||
window.down(buffer, cursor)
|
window.down(buffer, cursor)
|
||||||
window.horizontal_scroll(cursor)
|
window.horizontal_scroll(cursor)
|
||||||
print(f"scroll pos: {window.row}")
|
|
||||||
elif k == "KEY_PGDN":
|
elif k == "KEY_PGDN":
|
||||||
for _ in range(window.n_rows):
|
for _ in range(window.n_rows):
|
||||||
cursor.down(buffer)
|
cursor.down(buffer)
|
||||||
|
|
@ -470,39 +497,56 @@ def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: dis
|
||||||
window.horizontal_scroll(cursor)
|
window.horizontal_scroll(cursor)
|
||||||
elif k == "KEY_RIGHT":
|
elif k == "KEY_RIGHT":
|
||||||
right(window, buffer, cursor)
|
right(window, buffer, cursor)
|
||||||
|
elif k == "KEY_LEFT":
|
||||||
|
left(window, buffer, cursor)
|
||||||
elif k == "\n":
|
elif k == "\n":
|
||||||
leading_spaces = _count_leading_characters(buffer.lines[cursor.row], " ")
|
# Get leading whitespace from the current line
|
||||||
|
current_line = buffer.lines[cursor.row]
|
||||||
|
leading_spaces = _count_leading_characters(current_line, " ")
|
||||||
|
leading_tabs = _count_leading_characters(current_line, "\t")
|
||||||
|
|
||||||
|
# Split the line at the cursor
|
||||||
buffer.split(cursor)
|
buffer.split(cursor)
|
||||||
right(window, buffer, cursor)
|
|
||||||
|
# Move to the beginning of the next line
|
||||||
|
cursor.row += 1
|
||||||
|
cursor.col = 0
|
||||||
|
|
||||||
|
# Insert indentation in the correct order (first tabs, then spaces)
|
||||||
|
for i in range(leading_tabs):
|
||||||
|
buffer.insert(cursor, "\t")
|
||||||
|
right(window, buffer, cursor)
|
||||||
|
|
||||||
for i in range(leading_spaces):
|
for i in range(leading_spaces):
|
||||||
buffer.insert(cursor, " ")
|
buffer.insert(cursor, " ")
|
||||||
right(window, buffer, cursor)
|
right(window, buffer, cursor)
|
||||||
elif k in ("KEY_DELETE", "\x04"):
|
|
||||||
print("delete")
|
|
||||||
if cursor.row < len(buffer.lines) - 1 or \
|
|
||||||
cursor.col < len(buffer.lines[cursor.row]):
|
|
||||||
buffer.delete(cursor)
|
|
||||||
# try:
|
|
||||||
# visible_cursor.text = buffer.lines[cursor.row][cursor.col]
|
|
||||||
# except IndexError:
|
|
||||||
# visible_cursor.text = " "
|
|
||||||
|
|
||||||
|
# Update window scrolling
|
||||||
|
window.down(buffer, cursor)
|
||||||
|
window.horizontal_scroll(cursor)
|
||||||
|
|
||||||
|
elif k in ("KEY_DELETE", "\x04"):
|
||||||
|
if cursor.row < len(buffer.lines) - 1 or \
|
||||||
|
cursor.col < buffer.get_visual_length(cursor.row):
|
||||||
|
buffer.delete(cursor)
|
||||||
elif k in ("KEY_BACKSPACE", "\x7f", "\x08"):
|
elif k in ("KEY_BACKSPACE", "\x7f", "\x08"):
|
||||||
print(f"backspace {bytes(k, 'utf-8')}")
|
|
||||||
if (cursor.row, cursor.col) > (0, 0):
|
if (cursor.row, cursor.col) > (0, 0):
|
||||||
if cursor.col > 0 and buffer.lines[cursor.row][cursor.col-1] == " " and _only_spaces_before(cursor):
|
if cursor.col > 0 and only_spaces_before(buffer, cursor):
|
||||||
for i in range(4):
|
# Handle backspace with spaces
|
||||||
|
for i in range(min(TAB_SIZE, cursor.col)):
|
||||||
left(window, buffer, cursor)
|
left(window, buffer, cursor)
|
||||||
buffer.delete(cursor)
|
buffer.delete(cursor)
|
||||||
else:
|
else:
|
||||||
|
# Check if cursor is within a tab's visual space
|
||||||
|
if is_within_tab_range(buffer, cursor.row, cursor.col - 1):
|
||||||
|
actual_col = buffer._visual_to_actual_col(cursor.row, cursor.col - 1)
|
||||||
|
# Set cursor to the beginning of the tab
|
||||||
|
cursor.col = buffer.actual_to_visual_col(cursor.row, actual_col)
|
||||||
|
|
||||||
left(window, buffer, cursor)
|
left(window, buffer, cursor)
|
||||||
buffer.delete(cursor)
|
buffer.delete(cursor)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(f"unhandled k: {k}")
|
print(f"unhandled k: {k}")
|
||||||
print(f"unhandled K: {ord(k)}")
|
|
||||||
print(f"unhandled k: {bytes(k, 'utf-8')}")
|
|
||||||
|
|
||||||
|
|
||||||
if mouse is not None:
|
if mouse is not None:
|
||||||
pressed_btns = mouse.update()
|
pressed_btns = mouse.update()
|
||||||
|
|
@ -510,38 +554,58 @@ def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: dis
|
||||||
clicked_tile_coords[0] = mouse.x // 6
|
clicked_tile_coords[0] = mouse.x // 6
|
||||||
clicked_tile_coords[1] = mouse.y // 12
|
clicked_tile_coords[1] = mouse.y // 12
|
||||||
|
|
||||||
if clicked_tile_coords[0] > len(buffer.lines[clicked_tile_coords[1]+window.row]):
|
if clicked_tile_coords[1] < len(buffer.lines):
|
||||||
clicked_tile_coords[0] = len(buffer.lines[clicked_tile_coords[1]+window.row])
|
visual_length = buffer.get_visual_length(clicked_tile_coords[1])
|
||||||
cursor.row = clicked_tile_coords[1] + window.row
|
if clicked_tile_coords[0] > visual_length:
|
||||||
cursor.col = clicked_tile_coords[0] + window.col
|
clicked_tile_coords[0] = visual_length
|
||||||
|
|
||||||
# print("updating visible cursor")
|
cursor.row = clicked_tile_coords[1]
|
||||||
# print(f"anchored pos: {((cursor.col * 6) - 1, (cursor.row * 12) + 20)}")
|
cursor.col = clicked_tile_coords[0]
|
||||||
|
|
||||||
if (old_cursor_pos[0] - old_window_pos[0] != cursor.col - window.col or
|
# Update cursor highlighting if position changed
|
||||||
old_cursor_pos[1] - old_window_pos[1] != cursor.row - window.row):
|
if old_cursor_pos != (cursor.col, cursor.row):
|
||||||
# print(f"old cursor: {old_cursor_pos}, new: {(cursor.col, cursor.row)}")
|
# Clear old cursor position
|
||||||
# print(f"window (row,col): {window.row}, {window.col}")
|
clear_cursor_highlight(terminal_tilegrid, buffer, old_cursor_pos[1], old_cursor_pos[0])
|
||||||
terminal_tilegrid.pixel_shader[old_cursor_pos[0] - old_window_pos[0], old_cursor_pos[1] - old_window_pos[1]] = [0,1]
|
|
||||||
terminal_tilegrid.pixel_shader[cursor.col - window.col, cursor.row - window.row] = [1,0]
|
|
||||||
# print(f"old: {terminal_tilegrid.pixel_shader[old_cursor_pos[0], old_cursor_pos[1]]} new: {terminal_tilegrid.pixel_shader[cursor.col, cursor.row]}")
|
|
||||||
|
|
||||||
# visible_cursor.anchored_position = ((cursor.col * 6) - 1, (cursor.row * 12) + 20)
|
# Highlight new cursor position
|
||||||
|
highlight_cursor_position(terminal_tilegrid, buffer, cursor)
|
||||||
|
|
||||||
# visible_cursor.anchored_position = ((cursor.col * 6), ((cursor.row - window.row) * 12))
|
old_cursor_pos = (cursor.col, cursor.row)
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# visible_cursor.text = buffer.lines[cursor.row][cursor.col]
|
|
||||||
# except IndexError:
|
|
||||||
# visible_cursor.text = " "
|
|
||||||
|
|
||||||
|
|
||||||
old_cursor_pos = (cursor.col, cursor.row)
|
def highlight_cursor_position(terminal_tilegrid, buffer, cursor):
|
||||||
old_window_pos = (window.col, window.row)
|
"""Highlight the cursor position, handling tabs properly"""
|
||||||
|
if terminal_tilegrid is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if is_at_tab(buffer, cursor.row, cursor.col):
|
||||||
|
# If at a tab, highlight all positions that represent the tab
|
||||||
|
tab_positions = get_tab_visual_positions(buffer, cursor.row, cursor.col)
|
||||||
|
for pos in tab_positions:
|
||||||
|
terminal_tilegrid.pixel_shader[pos, cursor.row] = [1, 0]
|
||||||
|
else:
|
||||||
|
# Otherwise just highlight the current position
|
||||||
|
terminal_tilegrid.pixel_shader[cursor.col, cursor.row] = [1, 0]
|
||||||
|
|
||||||
|
|
||||||
|
def clear_cursor_highlight(terminal_tilegrid, buffer, row, col):
|
||||||
|
"""Clear cursor highlighting, handling tabs properly"""
|
||||||
|
if terminal_tilegrid is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if is_at_tab(buffer, row, col):
|
||||||
|
# If at a tab, clear all positions that represent the tab
|
||||||
|
tab_positions = get_tab_visual_positions(buffer, row, col)
|
||||||
|
for pos in tab_positions:
|
||||||
|
terminal_tilegrid.pixel_shader[pos, row] = [0, 1]
|
||||||
|
else:
|
||||||
|
# Otherwise just clear the current position
|
||||||
|
terminal_tilegrid.pixel_shader[col, row] = [0, 1]
|
||||||
|
|
||||||
|
|
||||||
def edit(filename, terminal=None, mouse=None, terminal_tilegrid=None):
|
def edit(filename, terminal=None, mouse=None, terminal_tilegrid=None):
|
||||||
with MaybeDisableReload():
|
with MaybeDisableReload():
|
||||||
if terminal is None:
|
if terminal is None:
|
||||||
return curses.wrapper(editor, filename)
|
return curses.wrapper(editor, filename)
|
||||||
else:
|
else:
|
||||||
return curses.custom_terminal_wrapper(terminal, editor, filename, mouse, terminal_tilegrid)
|
return curses.custom_terminal_wrapper(terminal, editor, filename, mouse, terminal_tilegrid)
|
||||||
|
|
@ -3,14 +3,13 @@ import os
|
||||||
|
|
||||||
import supervisor
|
import supervisor
|
||||||
from displayio import Group, Palette, TileGrid
|
from displayio import Group, Palette, TileGrid
|
||||||
|
import terminalio
|
||||||
from adafruit_display_text.bitmap_label import Label
|
from adafruit_display_text.bitmap_label import Label
|
||||||
from adafruit_editor import editor, picker
|
from adafruit_editor import editor, picker
|
||||||
from tilepalettemapper import TilePaletteMapper
|
from tilepalettemapper import TilePaletteMapper
|
||||||
from adafruit_argv_file import read_argv, write_argv
|
from adafruit_argv_file import read_argv, write_argv
|
||||||
from adafruit_fruitjam.peripherals import request_display_config
|
from adafruit_fruitjam.peripherals import request_display_config
|
||||||
from adafruit_usb_host_mouse import find_and_init_boot_mouse
|
from adafruit_usb_host_mouse import find_and_init_boot_mouse
|
||||||
import terminalio
|
|
||||||
import usb
|
|
||||||
|
|
||||||
print(f"cwd in editor/code.py: {os.getcwd()}")
|
print(f"cwd in editor/code.py: {os.getcwd()}")
|
||||||
|
|
||||||
|
|
@ -26,6 +25,7 @@ font_palette = Palette(2)
|
||||||
font_palette[0] = 0x000000
|
font_palette[0] = 0x000000
|
||||||
font_palette[1] = 0xFFFFFF
|
font_palette[1] = 0xFFFFFF
|
||||||
|
|
||||||
|
|
||||||
font = terminalio.FONT
|
font = terminalio.FONT
|
||||||
char_size = font.get_bounding_box()
|
char_size = font.get_bounding_box()
|
||||||
screen_size = (display.width // char_size[0], display.height // char_size[1])
|
screen_size = (display.width // char_size[0], display.height // char_size[1])
|
||||||
|
|
@ -37,10 +37,11 @@ highlight_palette[1] = 0xFFFFFF
|
||||||
highlight_palette[2] = 0xC9C9C9
|
highlight_palette[2] = 0xC9C9C9
|
||||||
|
|
||||||
|
|
||||||
tpm = TilePaletteMapper(highlight_palette, 2)
|
|
||||||
terminal_area = TileGrid(bitmap=font.bitmap, width=screen_size[0], height=screen_size[1],
|
|
||||||
tile_width=char_size[0], tile_height=char_size[1], pixel_shader=tpm)
|
|
||||||
|
|
||||||
|
terminal_area = TileGrid(bitmap=font.bitmap, width=screen_size[0], height=screen_size[1],
|
||||||
|
tile_width=char_size[0], tile_height=char_size[1])
|
||||||
|
|
||||||
|
tpm = TilePaletteMapper(highlight_palette, 2, terminal_area)
|
||||||
for x in range(screen_size[0]):
|
for x in range(screen_size[0]):
|
||||||
tpm[x,screen_size[1]-1] = [2,0]
|
tpm[x,screen_size[1]-1] = [2,0]
|
||||||
|
|
||||||
|
|
@ -62,14 +63,7 @@ if args is not None and len(args) > 0:
|
||||||
else:
|
else:
|
||||||
file = picker.pick_file(terminal)
|
file = picker.pick_file(terminal)
|
||||||
|
|
||||||
usb_device_count = 0
|
mouse = find_and_init_boot_mouse()
|
||||||
for dev in usb.core.find(find_all=True):
|
|
||||||
usb_device_count += 1
|
|
||||||
|
|
||||||
mouse = None
|
|
||||||
if usb_device_count > 1:
|
|
||||||
mouse = find_and_init_boot_mouse()
|
|
||||||
|
|
||||||
if mouse is not None:
|
if mouse is not None:
|
||||||
mouse.x = display.width - 6
|
mouse.x = display.width - 6
|
||||||
main_group.append(mouse.tilegrid)
|
main_group.append(mouse.tilegrid)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Adafruit CircuitPython 10.0.0-beta.0 on 2025-07-15; Adafruit Fruit Jam with rp2350b
|
Adafruit CircuitPython 10.0.0-alpha.4-2-g01da5c7c88-dirty on 2025-05-07; Adafruit Fruit Jam with rp2350b
|
||||||
Board ID:adafruit_fruit_jam
|
Board ID:adafruit_fruit_jam
|
||||||
UID:
|
UID:
|
||||||
boot.py output:
|
boot.py output:
|
||||||
|
|
|
||||||
|
|
@ -1,196 +0,0 @@
|
||||||
import hashlib
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
from urllib.request import urlretrieve
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from build import main as build_main
|
|
||||||
|
|
||||||
|
|
||||||
def get_file_sha256(file_path):
|
|
||||||
"""Calculates the SHA256 hash of a file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: The path to the file.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The SHA256 hash of the file as a hexadecimal string.
|
|
||||||
"""
|
|
||||||
sha256_hash = hashlib.sha256()
|
|
||||||
try:
|
|
||||||
with open(file_path, "rb") as f:
|
|
||||||
for chunk in iter(lambda: f.read(4096), b""):
|
|
||||||
sha256_hash.update(chunk)
|
|
||||||
except FileNotFoundError:
|
|
||||||
return "File not found."
|
|
||||||
return sha256_hash.hexdigest()
|
|
||||||
|
|
||||||
def print_hashes(hash_dict):
|
|
||||||
for filename in sorted(hash_dict.keys()):
|
|
||||||
print(f"{filename}: {hash_dict[filename]}")
|
|
||||||
|
|
||||||
|
|
||||||
def is_release_required():
|
|
||||||
"""
|
|
||||||
Checks if there are new versions of any apps. When new versions exist
|
|
||||||
a new release is required.
|
|
||||||
|
|
||||||
:return: True if there are new versions of any apps, and release is required, False otherwise.
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
dl_dir = Path("latest_dl")
|
|
||||||
if dl_dir.exists():
|
|
||||||
shutil.rmtree("latest_dl")
|
|
||||||
dl_dir.mkdir()
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# download built zips from most recent release
|
|
||||||
RELEASE_API_URL = "https://api.github.com/repos/adafruit/Fruit-Jam-OS/releases?per_page=1"
|
|
||||||
latest_release_obj = requests.get(RELEASE_API_URL).json()[0]
|
|
||||||
for asset in latest_release_obj["assets"]:
|
|
||||||
asset_dl_url = asset["browser_download_url"]
|
|
||||||
asset_filename = asset_dl_url.split("/")[-1]
|
|
||||||
urlretrieve(asset_dl_url, f"latest_dl/{asset_filename}")
|
|
||||||
|
|
||||||
# get sha256 hashes for each downloaded zip
|
|
||||||
downloaded_file_hashes = {}
|
|
||||||
for dl_file in Path("latest_dl").iterdir():
|
|
||||||
downloaded_file_hashes[dl_file.name] = get_file_sha256(dl_file)
|
|
||||||
|
|
||||||
# make a local build
|
|
||||||
build_main()
|
|
||||||
|
|
||||||
# get sha256 hashes for built zips
|
|
||||||
dist_file_hashes = {}
|
|
||||||
for dist_file in Path("dist").iterdir():
|
|
||||||
dist_file_hashes[dist_file.name] = get_file_sha256(dist_file)
|
|
||||||
|
|
||||||
print("Downloaded file hashes:")
|
|
||||||
print_hashes(downloaded_file_hashes)
|
|
||||||
|
|
||||||
print("Dist file hashes:")
|
|
||||||
print_hashes(dist_file_hashes)
|
|
||||||
|
|
||||||
# compare hashes
|
|
||||||
if dist_file_hashes != downloaded_file_hashes:
|
|
||||||
print("Zip hashes differ, a release is required.")
|
|
||||||
return True
|
|
||||||
|
|
||||||
print("Zip hashes match, no release required.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def parse_semantic_version(version_string):
|
|
||||||
"""Parse semantic version string and return (major, minor, patch)."""
|
|
||||||
|
|
||||||
# Match semantic version pattern
|
|
||||||
match = re.match(r'^(\d+)\.(\d+)\.(\d+)(?:-.*)?(?:\+.*)?$', version_string)
|
|
||||||
if not match:
|
|
||||||
raise ValueError(f"Invalid semantic version: {version_string}")
|
|
||||||
|
|
||||||
return int(match.group(1)), int(match.group(2)), int(match.group(3))
|
|
||||||
|
|
||||||
|
|
||||||
def increment_patch_version(version_string):
|
|
||||||
"""Increment patch version by 1."""
|
|
||||||
major, minor, patch = parse_semantic_version(version_string)
|
|
||||||
new_patch = patch + 1
|
|
||||||
return f"{major}.{minor}.{new_patch}"
|
|
||||||
|
|
||||||
|
|
||||||
def get_latest_release():
|
|
||||||
"""Fetch the latest release from GitHub API."""
|
|
||||||
url = f"https://api.github.com/repos/adafruit/Fruit-Jam-OS/releases/latest"
|
|
||||||
headers = {
|
|
||||||
"Authorization": f"token {os.getenv('GITHUB_TOKEN')}",
|
|
||||||
"Accept": "application/vnd.github.v3+json"
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.get(url, headers=headers)
|
|
||||||
|
|
||||||
if response.status_code != 200:
|
|
||||||
print(f"Error fetching latest release: {response.status_code}")
|
|
||||||
print(f"Response: {response.text}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
return response.json()
|
|
||||||
|
|
||||||
|
|
||||||
def create_release(tag_name):
|
|
||||||
"""Create a new GitHub release."""
|
|
||||||
url = f"https://api.github.com/repos/adafruit/Fruit-Jam-OS/releases"
|
|
||||||
headers = {
|
|
||||||
"Authorization": f"token {os.getenv('GITHUB_TOKEN')}",
|
|
||||||
"Accept": "application/vnd.github.v3+json",
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
}
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"tag_name": tag_name,
|
|
||||||
"name": tag_name,
|
|
||||||
"body": f"Release {tag_name}",
|
|
||||||
"draft": False,
|
|
||||||
"prerelease": False
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, headers=headers, data=json.dumps(data))
|
|
||||||
|
|
||||||
if response.status_code != 201:
|
|
||||||
print(f"Error creating release: {response.status_code}")
|
|
||||||
print(f"Response: {response.text}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
return response.json()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
if is_release_required():
|
|
||||||
if len(sys.argv) > 1 and sys.argv[1] == "make_release":
|
|
||||||
print(f"Creating release for Fruit Jam OS")
|
|
||||||
|
|
||||||
# Get latest release
|
|
||||||
latest_release = get_latest_release()
|
|
||||||
|
|
||||||
if latest_release:
|
|
||||||
latest_tag = latest_release["tag_name"]
|
|
||||||
print(f"Latest release: {latest_tag}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
new_tag = increment_patch_version(latest_tag)
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"Error parsing version: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
new_tag = "0.1.0"
|
|
||||||
|
|
||||||
print(f"Creating new release: {new_tag}")
|
|
||||||
|
|
||||||
new_release = create_release(
|
|
||||||
tag_name=new_tag,
|
|
||||||
)
|
|
||||||
|
|
||||||
#print(new_release)
|
|
||||||
|
|
||||||
github_output_path = os.environ.get('GITHUB_OUTPUT')
|
|
||||||
|
|
||||||
if github_output_path:
|
|
||||||
with open(github_output_path, 'a') as f:
|
|
||||||
f.write(f"release_created=true\n")
|
|
||||||
f.write(f"assets_upload_url={new_release['upload_url']}\n")
|
|
||||||
|
|
||||||
print(f"Successfully created release: {new_tag}")
|
|
||||||
print(f"Release URL: {new_release['html_url']}")
|
|
||||||
else:
|
|
||||||
github_output_path = os.environ.get('GITHUB_OUTPUT')
|
|
||||||
|
|
||||||
if github_output_path:
|
|
||||||
with open(github_output_path, 'a') as f:
|
|
||||||
f.write(f"release_created=false\n")
|
|
||||||
f.write(f"assets_upload_url=None\n")
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
import os
|
||||||
|
|
||||||
import supervisor
|
import supervisor
|
||||||
from adafruit_argv_file import read_argv, write_argv
|
from adafruit_argv_file import read_argv, write_argv
|
||||||
|
import json
|
||||||
import storage
|
import storage
|
||||||
|
|
||||||
supervisor.runtime.autoreload = False
|
supervisor.runtime.autoreload = False
|
||||||
|
|
@ -40,8 +42,4 @@ if args is not None and len(args) > 0:
|
||||||
working_directory="/".join(next_code_file.split("/")[:-1]))
|
working_directory="/".join(next_code_file.split("/")[:-1]))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# skip boot animation if no display
|
supervisor.set_next_code_file("boot_animation.py")
|
||||||
if supervisor.runtime.display is None:
|
|
||||||
supervisor.set_next_code_file("code.py")
|
|
||||||
else:
|
|
||||||
supervisor.set_next_code_file("boot_animation.py")
|
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,17 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
import gc
|
import gc
|
||||||
import json
|
|
||||||
|
|
||||||
import board
|
import board
|
||||||
|
import displayio
|
||||||
import supervisor
|
import supervisor
|
||||||
from displayio import TileGrid, Group
|
from displayio import OnDiskBitmap, TileGrid, Group
|
||||||
import adafruit_imageload
|
import adafruit_imageload
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
import adafruit_tlv320
|
import adafruit_tlv320
|
||||||
from audiocore import WaveFile
|
from audiocore import WaveFile
|
||||||
import audiobusio
|
import audiobusio
|
||||||
import adafruit_pathlib as pathlib
|
|
||||||
|
|
||||||
launcher_config = {}
|
|
||||||
if pathlib.Path("launcher.conf.json").exists():
|
|
||||||
with open("launcher.conf.json", "r") as f:
|
|
||||||
launcher_config = json.load(f)
|
|
||||||
|
|
||||||
BOX_SIZE = (235, 107)
|
BOX_SIZE = (235, 107)
|
||||||
TARGET_FPS = 70
|
TARGET_FPS = 70
|
||||||
|
|
@ -27,38 +21,18 @@ display = supervisor.runtime.display
|
||||||
display.auto_refresh = False
|
display.auto_refresh = False
|
||||||
|
|
||||||
i2c = board.I2C()
|
i2c = board.I2C()
|
||||||
# Check if DAC is connected
|
dac = adafruit_tlv320.TLV320DAC3100(i2c)
|
||||||
while not i2c.try_lock():
|
|
||||||
time.sleep(0.01)
|
|
||||||
if 0x18 in i2c.scan():
|
|
||||||
ltv320_present = True
|
|
||||||
else:
|
|
||||||
ltv320_present = False
|
|
||||||
i2c.unlock()
|
|
||||||
|
|
||||||
if ltv320_present:
|
# set sample rate & bit depth
|
||||||
dac = adafruit_tlv320.TLV320DAC3100(i2c)
|
dac.configure_clocks(sample_rate=11030, bit_depth=16)
|
||||||
|
|
||||||
# set sample rate & bit depth
|
# use headphones
|
||||||
dac.configure_clocks(sample_rate=11030, bit_depth=16)
|
dac.headphone_output = True
|
||||||
|
dac.headphone_volume = -15 # dB
|
||||||
|
|
||||||
if "sound" in launcher_config:
|
wave_file = open("/boot_animation/ada_fruitjam_boot_jingle.wav", "rb")
|
||||||
if launcher_config["sound"] == "speaker":
|
wave = WaveFile(wave_file)
|
||||||
# use speaker
|
audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN)
|
||||||
dac.speaker_output = True
|
|
||||||
dac.speaker_volume = -40
|
|
||||||
else:
|
|
||||||
# use headphones
|
|
||||||
dac.headphone_output = True
|
|
||||||
dac.headphone_volume = -15 # dB
|
|
||||||
else:
|
|
||||||
# default to headphones
|
|
||||||
dac.headphone_output = True
|
|
||||||
dac.headphone_volume = -15 # dB
|
|
||||||
|
|
||||||
wave_file = open("/boot_animation/ada_fruitjam_boot_jingle.wav", "rb")
|
|
||||||
wave = WaveFile(wave_file)
|
|
||||||
audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN)
|
|
||||||
|
|
||||||
|
|
||||||
class OvershootAnimator:
|
class OvershootAnimator:
|
||||||
|
|
@ -648,8 +622,7 @@ display.root_group = main_group
|
||||||
|
|
||||||
start_time = time.monotonic()
|
start_time = time.monotonic()
|
||||||
|
|
||||||
if ltv320_present:
|
audio.play(wave)
|
||||||
audio.play(wave)
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
now = time.monotonic()
|
now = time.monotonic()
|
||||||
|
|
@ -696,9 +669,8 @@ while True:
|
||||||
if not still_going:
|
if not still_going:
|
||||||
break
|
break
|
||||||
|
|
||||||
if ltv320_present:
|
while audio.playing:
|
||||||
while audio.playing:
|
pass
|
||||||
pass
|
|
||||||
|
|
||||||
supervisor.set_next_code_file("code.py")
|
supervisor.set_next_code_file("code.py")
|
||||||
supervisor.reload()
|
supervisor.reload()
|
||||||
288
src/code.py
288
src/code.py
|
|
@ -8,23 +8,27 @@ import array
|
||||||
import atexit
|
import atexit
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
import displayio
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import displayio
|
||||||
|
|
||||||
import supervisor
|
import supervisor
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import terminalio
|
import terminalio
|
||||||
import usb
|
|
||||||
|
|
||||||
import adafruit_pathlib as pathlib
|
import adafruit_pathlib as pathlib
|
||||||
from adafruit_bitmap_font import bitmap_font
|
from adafruit_bitmap_font import bitmap_font
|
||||||
from adafruit_display_text.text_box import TextBox
|
from adafruit_display_text.text_box import TextBox
|
||||||
from adafruit_display_text.bitmap_label import Label
|
from adafruit_display_text.bitmap_label import Label
|
||||||
|
|
||||||
from adafruit_displayio_layout.layouts.grid_layout import GridLayout
|
from adafruit_displayio_layout.layouts.grid_layout import GridLayout
|
||||||
from adafruit_anchored_tilegrid import AnchoredTileGrid
|
from adafruit_anchored_tilegrid import AnchoredTileGrid
|
||||||
import adafruit_imageload
|
import adafruit_imageload
|
||||||
import adafruit_usb_host_descriptors
|
|
||||||
|
from adafruit_usb_host_mouse import find_and_init_boot_mouse
|
||||||
from adafruit_anchored_group import AnchoredGroup
|
from adafruit_anchored_group import AnchoredGroup
|
||||||
from adafruit_fruitjam.peripherals import request_display_config, VALID_DISPLAY_SIZES
|
from adafruit_fruitjam.peripherals import request_display_config
|
||||||
from adafruit_argv_file import read_argv, write_argv
|
from adafruit_argv_file import read_argv, write_argv
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
@ -53,28 +57,13 @@ if args is not None and len(args) > 0:
|
||||||
print(f"launching: {next_code_file}")
|
print(f"launching: {next_code_file}")
|
||||||
supervisor.reload()
|
supervisor.reload()
|
||||||
|
|
||||||
if (width_config := os.getenv("CIRCUITPY_DISPLAY_WIDTH")) is not None:
|
request_display_config(720, 400)
|
||||||
if width_config not in [x[0] for x in VALID_DISPLAY_SIZES]:
|
|
||||||
raise ValueError(f"Invalid display size. Must be one of: {VALID_DISPLAY_SIZES}")
|
|
||||||
for display_size in VALID_DISPLAY_SIZES:
|
|
||||||
if display_size[0] == width_config:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
display_size = (720, 400)
|
|
||||||
request_display_config(*display_size)
|
|
||||||
display = supervisor.runtime.display
|
display = supervisor.runtime.display
|
||||||
|
|
||||||
scale = 1
|
scale = 1
|
||||||
if display.width > 360:
|
if display.width > 360:
|
||||||
scale = 2
|
scale = 2
|
||||||
|
|
||||||
launcher_config = {}
|
|
||||||
if pathlib.Path("launcher.conf.json").exists():
|
|
||||||
with open("launcher.conf.json", "r") as f:
|
|
||||||
launcher_config = json.load(f)
|
|
||||||
if "palette" not in launcher_config:
|
|
||||||
launcher_config["palette"] = {}
|
|
||||||
|
|
||||||
font_file = "/fonts/terminal.lvfontbin"
|
font_file = "/fonts/terminal.lvfontbin"
|
||||||
font = bitmap_font.load_font(font_file)
|
font = bitmap_font.load_font(font_file)
|
||||||
scaled_group = displayio.Group(scale=scale)
|
scaled_group = displayio.Group(scale=scale)
|
||||||
|
|
@ -86,88 +75,62 @@ display.root_group = main_group
|
||||||
|
|
||||||
background_bmp = displayio.Bitmap(display.width, display.height, 1)
|
background_bmp = displayio.Bitmap(display.width, display.height, 1)
|
||||||
bg_palette = displayio.Palette(1)
|
bg_palette = displayio.Palette(1)
|
||||||
bg_palette[0] = int(launcher_config["palette"].get("bg", "0x222222"), 16)
|
bg_palette[0] = 0x222222
|
||||||
bg_tg = displayio.TileGrid(bitmap=background_bmp, pixel_shader=bg_palette)
|
bg_tg = displayio.TileGrid(bitmap=background_bmp, pixel_shader=bg_palette)
|
||||||
scaled_group.append(bg_tg)
|
scaled_group.append(bg_tg)
|
||||||
|
|
||||||
# load the mouse cursor bitmap
|
mouse = find_and_init_boot_mouse()
|
||||||
mouse_bmp = displayio.OnDiskBitmap("launcher_assets/mouse_cursor.bmp")
|
|
||||||
|
|
||||||
# make the background pink pixels transparent
|
WIDTH = 280
|
||||||
mouse_bmp.pixel_shader.make_transparent(0)
|
HEIGHT = 182
|
||||||
|
|
||||||
# create a TileGrid for the mouse, using its bitmap and pixel_shader
|
|
||||||
mouse_tg = displayio.TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader)
|
|
||||||
|
|
||||||
# move it to the center of the display
|
|
||||||
mouse_tg.x = display.width // (2 * scale)
|
|
||||||
mouse_tg.y = display.height // (2 * scale)
|
|
||||||
# 046d:c52f
|
|
||||||
|
|
||||||
# mouse = usb.core.find(idVendor=0x046d, idProduct=0xc52f)
|
|
||||||
|
|
||||||
DIR_IN = 0x80
|
|
||||||
mouse_interface_index, mouse_endpoint_address = None, None
|
|
||||||
mouse = None
|
|
||||||
mouse_was_attached = None
|
|
||||||
|
|
||||||
if "use_mouse" in launcher_config and launcher_config["use_mouse"]:
|
|
||||||
|
|
||||||
# scan for connected USB device and loop over any found
|
|
||||||
print("scanning usb")
|
|
||||||
for device in usb.core.find(find_all=True):
|
|
||||||
# print device info
|
|
||||||
print(f"{device.idVendor:04x}:{device.idProduct:04x}")
|
|
||||||
print(device.manufacturer, device.product)
|
|
||||||
print()
|
|
||||||
config_descriptor = adafruit_usb_host_descriptors.get_configuration_descriptor(
|
|
||||||
device, 0
|
|
||||||
)
|
|
||||||
print(config_descriptor)
|
|
||||||
|
|
||||||
_possible_interface_index, _possible_endpoint_address = adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device)
|
|
||||||
if _possible_interface_index is not None and _possible_endpoint_address is not None:
|
|
||||||
mouse = device
|
|
||||||
mouse_interface_index = _possible_interface_index
|
|
||||||
mouse_endpoint_address = _possible_endpoint_address
|
|
||||||
print(f"mouse interface: {mouse_interface_index} endpoint_address: {hex(mouse_endpoint_address)}")
|
|
||||||
|
|
||||||
mouse_was_attached = None
|
|
||||||
if mouse is not None:
|
|
||||||
# detach the kernel driver if needed
|
|
||||||
if mouse.is_kernel_driver_active(0):
|
|
||||||
mouse_was_attached = True
|
|
||||||
mouse.detach_kernel_driver(0)
|
|
||||||
else:
|
|
||||||
mouse_was_attached = False
|
|
||||||
|
|
||||||
# set configuration on the mouse so we can use it
|
|
||||||
mouse.set_configuration()
|
|
||||||
|
|
||||||
mouse_buf = array.array("b", [0] * 8)
|
|
||||||
|
|
||||||
WIDTH = int(298 / 360 * display.width // scale)
|
|
||||||
HEIGHT = int(182 / 200 * display.height // scale)
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"menu_title": "Launcher Menu",
|
"menu_title": "Launcher Menu",
|
||||||
"width": 3,
|
"width": 3,
|
||||||
"height": 2,
|
"height": 2,
|
||||||
|
"apps": [
|
||||||
|
{
|
||||||
|
"title": "🐍Snake🐍",
|
||||||
|
"icon": "icon_snake.bmp",
|
||||||
|
"file": "code_snake_game.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Nyan😺Flap",
|
||||||
|
"icon": "icon_flappynyan.bmp",
|
||||||
|
"file": "code_flappy_nyan.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Memory🧠",
|
||||||
|
"icon": "icon_memory.bmp",
|
||||||
|
"file": "code_memory.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Matrix",
|
||||||
|
"icon": "/apps/matrix/icon.bmp",
|
||||||
|
"file": "/apps/matrix/code.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Breakout",
|
||||||
|
"icon": "icon_breakout.bmp",
|
||||||
|
"file": "code_breakout.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Paint🖌️",
|
||||||
|
"icon": "icon_paint.bmp",
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_width = WIDTH // config["width"]
|
cell_width = WIDTH // config["width"]
|
||||||
cell_height = HEIGHT // config["height"]
|
|
||||||
page_size = config["width"] * config["height"]
|
|
||||||
|
|
||||||
default_icon_bmp, default_icon_palette = adafruit_imageload.load("launcher_assets/default_icon.bmp")
|
default_icon_bmp, default_icon_palette = adafruit_imageload.load("launcher_assets/default_icon.bmp")
|
||||||
default_icon_palette.make_transparent(0)
|
default_icon_palette.make_transparent(0)
|
||||||
menu_grid = GridLayout(x=(display.width // scale - WIDTH) // 2,
|
menu_grid = GridLayout(x=40, y=16, width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
|
||||||
y=(display.height // scale - HEIGHT) // 2,
|
|
||||||
width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
|
|
||||||
divider_lines=False)
|
divider_lines=False)
|
||||||
scaled_group.append(menu_grid)
|
scaled_group.append(menu_grid)
|
||||||
|
|
||||||
menu_title_txt = Label(font, text="Fruit Jam OS", color=int(launcher_config["palette"].get("fg", "0xffffff"), 16))
|
menu_title_txt = Label(font, text="Fruit Jam OS")
|
||||||
menu_title_txt.anchor_point = (0.5, 0.5)
|
menu_title_txt.anchor_point = (0.5, 0.5)
|
||||||
menu_title_txt.anchored_position = (display.width // (2 * scale), 2)
|
menu_title_txt.anchored_position = (display.width // (2 * scale), 2)
|
||||||
scaled_group.append(menu_title_txt)
|
scaled_group.append(menu_title_txt)
|
||||||
|
|
@ -175,6 +138,7 @@ scaled_group.append(menu_title_txt)
|
||||||
app_titles = []
|
app_titles = []
|
||||||
apps = []
|
apps = []
|
||||||
app_path = pathlib.Path("/apps")
|
app_path = pathlib.Path("/apps")
|
||||||
|
i = 0
|
||||||
|
|
||||||
pages = [{}]
|
pages = [{}]
|
||||||
|
|
||||||
|
|
@ -211,22 +175,10 @@ for path in app_path.iterdir():
|
||||||
apps.append({
|
apps.append({
|
||||||
"title": title,
|
"title": title,
|
||||||
"icon": str(icon_file.absolute()) if icon_file is not None else None,
|
"icon": str(icon_file.absolute()) if icon_file is not None else None,
|
||||||
"file": str(code_file.absolute()),
|
"file": str(code_file.absolute())
|
||||||
"dir": path
|
|
||||||
})
|
})
|
||||||
|
|
||||||
apps = sorted(apps, key=lambda app: app["title"].lower())
|
i += 1
|
||||||
|
|
||||||
print("launcher config", launcher_config)
|
|
||||||
if "favorites" in launcher_config:
|
|
||||||
|
|
||||||
for favorite_app in reversed(launcher_config["favorites"]):
|
|
||||||
print("checking favorite", favorite_app)
|
|
||||||
for app in apps:
|
|
||||||
print(f"checking app: {app["dir"]}")
|
|
||||||
if app["dir"] == f"/apps/{favorite_app}":
|
|
||||||
apps.remove(app)
|
|
||||||
apps.insert(0, app)
|
|
||||||
|
|
||||||
|
|
||||||
def reuse_cell(grid_coords):
|
def reuse_cell(grid_coords):
|
||||||
|
|
@ -249,9 +201,8 @@ def _create_cell_group(app):
|
||||||
cell_group.append(icon_tg)
|
cell_group.append(icon_tg)
|
||||||
|
|
||||||
icon_tg.x = cell_width // 2 - icon_tg.tile_width // 2
|
icon_tg.x = cell_width // 2 - icon_tg.tile_width // 2
|
||||||
title_txt = TextBox(font, text=app["title"], width=cell_width, height=18,
|
title_txt = TextBox(font, text=app["title"], width=WIDTH // config["width"], height=18,
|
||||||
align=TextBox.ALIGN_CENTER, color=int(launcher_config["palette"].get("fg", "0xffffff"), 16))
|
align=TextBox.ALIGN_CENTER)
|
||||||
icon_tg.y = (cell_height - icon_tg.tile_height - title_txt.height) // 2
|
|
||||||
cell_group.append(title_txt)
|
cell_group.append(title_txt)
|
||||||
title_txt.anchor_point = (0, 0)
|
title_txt.anchor_point = (0, 0)
|
||||||
title_txt.anchored_position = (0, icon_tg.y + icon_tg.tile_height)
|
title_txt.anchored_position = (0, icon_tg.y + icon_tg.tile_height)
|
||||||
|
|
@ -271,8 +222,8 @@ def _reuse_cell_group(app, cell_group):
|
||||||
icon_tg.pixel_shader = icon_palette
|
icon_tg.pixel_shader = icon_palette
|
||||||
|
|
||||||
icon_tg.x = cell_width // 2 - icon_tg.tile_width // 2
|
icon_tg.x = cell_width // 2 - icon_tg.tile_width // 2
|
||||||
# title_txt = TextBox(font, text=app["title"], width=cell_width, height=18,
|
# title_txt = TextBox(font, text=app["title"], width=WIDTH // config["width"], height=18,
|
||||||
# align=TextBox.ALIGN_CENTER, color=int(launcher_config["palette"].get("fg", "0xffffff"), 16))
|
# align=TextBox.ALIGN_CENTER)
|
||||||
# cell_group.append(title_txt)
|
# cell_group.append(title_txt)
|
||||||
title_txt = cell_group[1]
|
title_txt = cell_group[1]
|
||||||
title_txt.text = app["title"]
|
title_txt.text = app["title"]
|
||||||
|
|
@ -293,13 +244,10 @@ def _unhide_cell_group(cell_group):
|
||||||
|
|
||||||
|
|
||||||
def display_page(page_index):
|
def display_page(page_index):
|
||||||
max_pages = math.ceil(len(apps) / page_size)
|
for grid_index in range(6):
|
||||||
page_txt.text = f"{page_index + 1}/{max_pages}"
|
|
||||||
|
|
||||||
for grid_index in range(page_size):
|
|
||||||
grid_pos = (grid_index % config["width"], grid_index // config["width"])
|
grid_pos = (grid_index % config["width"], grid_index // config["width"])
|
||||||
try:
|
try:
|
||||||
cur_app = apps[grid_index + (page_index * page_size)]
|
cur_app = apps[grid_index + (page_index * 6)]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
try:
|
try:
|
||||||
cell_group = menu_grid.get_content(grid_pos)
|
cell_group = menu_grid.get_content(grid_pos)
|
||||||
|
|
@ -321,11 +269,6 @@ def display_page(page_index):
|
||||||
print(f"{grid_index} | {grid_index % config["width"], grid_index // config["width"]}")
|
print(f"{grid_index} | {grid_index % config["width"], grid_index // config["width"]}")
|
||||||
|
|
||||||
|
|
||||||
page_txt = Label(terminalio.FONT, text="", scale=scale, color=int(launcher_config["palette"].get("fg", "0xffffff"), 16))
|
|
||||||
page_txt.anchor_point = (1.0, 1.0)
|
|
||||||
page_txt.anchored_position = (display.width - 2, display.height - 2)
|
|
||||||
main_group.append(page_txt)
|
|
||||||
|
|
||||||
cur_page = 0
|
cur_page = 0
|
||||||
display_page(cur_page)
|
display_page(cur_page)
|
||||||
|
|
||||||
|
|
@ -333,34 +276,35 @@ left_bmp, left_palette = adafruit_imageload.load("launcher_assets/arrow_left.bmp
|
||||||
left_palette.make_transparent(0)
|
left_palette.make_transparent(0)
|
||||||
right_bmp, right_palette = adafruit_imageload.load("launcher_assets/arrow_right.bmp")
|
right_bmp, right_palette = adafruit_imageload.load("launcher_assets/arrow_right.bmp")
|
||||||
right_palette.make_transparent(0)
|
right_palette.make_transparent(0)
|
||||||
if "arrow" in launcher_config["palette"]:
|
|
||||||
left_palette[2] = right_palette[2] = int(launcher_config["palette"].get("arrow"), 16)
|
|
||||||
|
|
||||||
left_tg = AnchoredTileGrid(bitmap=left_bmp, pixel_shader=left_palette)
|
left_tg = AnchoredTileGrid(bitmap=left_bmp, pixel_shader=left_palette)
|
||||||
left_tg.anchor_point = (0, 0.5)
|
left_tg.anchor_point = (0, 0.5)
|
||||||
left_tg.anchored_position = (0, (display.height // 2 // scale) - 2)
|
left_tg.anchored_position = (4, (display.height // 2 // scale) - 2)
|
||||||
|
|
||||||
right_tg = AnchoredTileGrid(bitmap=right_bmp, pixel_shader=right_palette)
|
right_tg = AnchoredTileGrid(bitmap=right_bmp, pixel_shader=right_palette)
|
||||||
right_tg.anchor_point = (1.0, 0.5)
|
right_tg.anchor_point = (1.0, 0.5)
|
||||||
right_tg.anchored_position = ((display.width // scale), (display.height // 2 // scale) - 2)
|
right_tg.anchored_position = ((display.width // scale) - 4, (display.height // 2 // scale) - 2)
|
||||||
original_arrow_btn_color = left_palette[2]
|
original_arrow_btn_color = left_palette[2]
|
||||||
|
|
||||||
scaled_group.append(left_tg)
|
scaled_group.append(left_tg)
|
||||||
scaled_group.append(right_tg)
|
scaled_group.append(right_tg)
|
||||||
|
|
||||||
if len(apps) <= page_size:
|
if len(apps) <= 6:
|
||||||
right_tg.hidden = True
|
right_tg.hidden = True
|
||||||
left_tg.hidden = True
|
left_tg.hidden = True
|
||||||
|
|
||||||
if mouse:
|
if mouse is not None:
|
||||||
scaled_group.append(mouse_tg)
|
mouse.scale = 2
|
||||||
|
mouse.x = display.width - 6
|
||||||
|
scaled_group.append(mouse.tilegrid)
|
||||||
|
|
||||||
|
|
||||||
help_txt = Label(terminalio.FONT, text="[Arrow]: Move [E]: Edit [Enter]: Run [1-9]: Page",
|
help_txt = Label(terminalio.FONT, text="[Arrow]: Move\n[E]: Edit\n[Enter]: Run")
|
||||||
color=int(launcher_config["palette"].get("fg", "0xffffff"), 16))
|
# help_txt = TextBox(terminalio.FONT, width=88, height=30, align=TextBox.ALIGN_RIGHT, background_color=0x008800, text="[E]: Edit\n[Enter]: Run")
|
||||||
|
help_txt.anchor_point = (0, 0)
|
||||||
|
|
||||||
help_txt.anchor_point = (0.0, 1.0)
|
help_txt.anchored_position = (2, 2)
|
||||||
help_txt.anchored_position = (2, display.height-2)
|
# help_txt.anchored_position = (display.width - 89, 1)
|
||||||
|
|
||||||
print(help_txt.bounding_box)
|
print(help_txt.bounding_box)
|
||||||
main_group.append(help_txt)
|
main_group.append(help_txt)
|
||||||
|
|
@ -372,8 +316,8 @@ def atexit_callback():
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
print("inside atexit callback")
|
print("inside atexit callback")
|
||||||
if mouse_was_attached and not mouse.is_kernel_driver_active(0):
|
if mouse is not None:
|
||||||
mouse.attach_kernel_driver(0)
|
mouse.release()
|
||||||
|
|
||||||
|
|
||||||
atexit.register(atexit_callback)
|
atexit.register(atexit_callback)
|
||||||
|
|
@ -393,27 +337,15 @@ def change_selected(new_selected):
|
||||||
|
|
||||||
# tuple means an item in the grid is selected
|
# tuple means an item in the grid is selected
|
||||||
if isinstance(new_selected, tuple):
|
if isinstance(new_selected, tuple):
|
||||||
menu_grid.get_content(new_selected)[1].background_color = int(launcher_config["palette"].get("accent", "0x008800"), 16)
|
menu_grid.get_content(new_selected)[1].background_color = 0x008800
|
||||||
# TileGrid means arrow is selected
|
# TileGrid means arrow is selected
|
||||||
elif isinstance(new_selected, AnchoredTileGrid):
|
elif isinstance(new_selected, AnchoredTileGrid):
|
||||||
new_selected.pixel_shader[2] = int(launcher_config["palette"].get("accent", "0x008800"), 16)
|
new_selected.pixel_shader[2] = 0x008800
|
||||||
selected = new_selected
|
selected = new_selected
|
||||||
|
|
||||||
|
|
||||||
change_selected((0, 0))
|
change_selected((0, 0))
|
||||||
|
|
||||||
def page_right():
|
|
||||||
global cur_page
|
|
||||||
if cur_page < math.ceil(len(apps) / page_size) - 1:
|
|
||||||
cur_page += 1
|
|
||||||
display_page(cur_page)
|
|
||||||
|
|
||||||
def page_left():
|
|
||||||
global cur_page
|
|
||||||
if cur_page > 0:
|
|
||||||
cur_page -= 1
|
|
||||||
display_page(cur_page)
|
|
||||||
|
|
||||||
|
|
||||||
def handle_key_press(key):
|
def handle_key_press(key):
|
||||||
global index, editor_index, cur_page
|
global index, editor_index, cur_page
|
||||||
|
|
@ -421,7 +353,7 @@ def handle_key_press(key):
|
||||||
# up key
|
# up key
|
||||||
if key == "\x1b[A":
|
if key == "\x1b[A":
|
||||||
if isinstance(selected, tuple):
|
if isinstance(selected, tuple):
|
||||||
change_selected((selected[0], (selected[1] - 1) % config["height"]))
|
change_selected((selected[0], (selected[1] - 1) % 2))
|
||||||
elif selected is left_tg:
|
elif selected is left_tg:
|
||||||
change_selected((0, 0))
|
change_selected((0, 0))
|
||||||
elif selected is right_tg:
|
elif selected is right_tg:
|
||||||
|
|
@ -431,7 +363,7 @@ def handle_key_press(key):
|
||||||
# down key
|
# down key
|
||||||
elif key == "\x1b[B":
|
elif key == "\x1b[B":
|
||||||
if isinstance(selected, tuple):
|
if isinstance(selected, tuple):
|
||||||
change_selected((selected[0], (selected[1] + 1) % config["height"]))
|
change_selected((selected[0], (selected[1] + 1) % 2))
|
||||||
elif selected is left_tg:
|
elif selected is left_tg:
|
||||||
change_selected((0, 1))
|
change_selected((0, 1))
|
||||||
elif selected is right_tg:
|
elif selected is right_tg:
|
||||||
|
|
@ -446,7 +378,7 @@ def handle_key_press(key):
|
||||||
elif not left_tg.hidden:
|
elif not left_tg.hidden:
|
||||||
change_selected(left_tg)
|
change_selected(left_tg)
|
||||||
else:
|
else:
|
||||||
change_selected(((selected[0] - 1) % config["width"], selected[1]))
|
change_selected(((selected[0] - 1) % 3, selected[1]))
|
||||||
elif selected is left_tg:
|
elif selected is left_tg:
|
||||||
change_selected(right_tg)
|
change_selected(right_tg)
|
||||||
elif selected is right_tg:
|
elif selected is right_tg:
|
||||||
|
|
@ -460,7 +392,7 @@ def handle_key_press(key):
|
||||||
elif not right_tg.hidden:
|
elif not right_tg.hidden:
|
||||||
change_selected(right_tg)
|
change_selected(right_tg)
|
||||||
else:
|
else:
|
||||||
change_selected(((selected[0] + 1) % config["width"], selected[1]))
|
change_selected(((selected[0] + 1) % 3, selected[1]))
|
||||||
elif selected is left_tg:
|
elif selected is left_tg:
|
||||||
change_selected((0, 0))
|
change_selected((0, 0))
|
||||||
elif selected is right_tg:
|
elif selected is right_tg:
|
||||||
|
|
@ -468,38 +400,33 @@ def handle_key_press(key):
|
||||||
|
|
||||||
elif key == "\n":
|
elif key == "\n":
|
||||||
if isinstance(selected, tuple):
|
if isinstance(selected, tuple):
|
||||||
index = (selected[1] * config["width"] + selected[0]) + (cur_page * page_size)
|
index = (selected[1] * 3 + selected[0]) + (cur_page * 6)
|
||||||
if index >= len(apps):
|
if index >= len(apps):
|
||||||
index = None
|
index = None
|
||||||
print("go!")
|
print("go!")
|
||||||
elif selected is left_tg:
|
elif selected is left_tg:
|
||||||
page_left()
|
if cur_page > 0:
|
||||||
|
cur_page -= 1
|
||||||
|
display_page(cur_page)
|
||||||
|
|
||||||
elif selected is right_tg:
|
elif selected is right_tg:
|
||||||
page_right()
|
if cur_page < math.ceil(len(apps) / 6) - 1:
|
||||||
|
cur_page += 1
|
||||||
|
display_page(cur_page)
|
||||||
|
|
||||||
elif key == "e":
|
elif key == "e":
|
||||||
if isinstance(selected, tuple):
|
if isinstance(selected, tuple):
|
||||||
editor_index = (selected[1] * config["width"] + selected[0]) + (cur_page * page_size)
|
editor_index = (selected[1] * 3 + selected[0]) + (cur_page * 6)
|
||||||
if editor_index >= len(apps):
|
if editor_index >= len(apps):
|
||||||
editor_index = None
|
editor_index = None
|
||||||
|
|
||||||
print("go!")
|
print("go!")
|
||||||
elif key in "123456789":
|
|
||||||
if key != "9":
|
|
||||||
requested_page = int(key)
|
|
||||||
max_page = math.ceil(len(apps) / page_size)
|
|
||||||
if requested_page <= max_page:
|
|
||||||
cur_page = requested_page - 1
|
|
||||||
display_page(requested_page-1)
|
|
||||||
else: # key == 9
|
|
||||||
max_page = math.ceil(len(apps) / page_size)
|
|
||||||
cur_page = max_page - 1
|
|
||||||
display_page(max_page - 1)
|
|
||||||
else:
|
else:
|
||||||
print(f"unhandled key: {repr(key)}")
|
print(f"unhandled key: {repr(key)}")
|
||||||
|
|
||||||
|
|
||||||
print(f"apps: {apps}")
|
print(f"apps: {apps}")
|
||||||
print(mouse_interface_index, mouse_endpoint_address)
|
# print(mouse_interface_index, mouse_endpoint_address)
|
||||||
while True:
|
while True:
|
||||||
index = None
|
index = None
|
||||||
editor_index = None
|
editor_index = None
|
||||||
|
|
@ -512,35 +439,26 @@ while True:
|
||||||
|
|
||||||
handle_key_press(c)
|
handle_key_press(c)
|
||||||
print("selected", selected)
|
print("selected", selected)
|
||||||
# app_titles[selected].background_color = int(launcher_config["palette"].get("accent", "0x008800"), 16)
|
# app_titles[selected].background_color = 0x008800
|
||||||
|
|
||||||
if mouse:
|
if mouse:
|
||||||
try:
|
pressed_btns = mouse.update()
|
||||||
# attempt to read data from the mouse
|
|
||||||
# 10ms timeout, so we don't block long if there
|
|
||||||
# is no data
|
|
||||||
count = mouse.read(mouse_endpoint_address, mouse_buf, timeout=20)
|
|
||||||
except usb.core.USBTimeoutError:
|
|
||||||
# skip the rest of the loop if there is no data
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
# update the mouse tilegrid x and y coordinates
|
if pressed_btns is not None and "left" in pressed_btns:
|
||||||
# based on the delta values read from the mouse
|
print("left click")
|
||||||
if count > 0:
|
clicked_cell = menu_grid.which_cell_contains((mouse.x, mouse.y))
|
||||||
mouse_tg.x = max(0, min((display.width // scale) - 1, mouse_tg.x + mouse_buf[1]))
|
if clicked_cell is not None:
|
||||||
mouse_tg.y = max(0, min((display.height // scale) - 1, mouse_tg.y + mouse_buf[2]))
|
index = clicked_cell[1] * config["width"] + clicked_cell[0]
|
||||||
|
|
||||||
if mouse_buf[0] & (1 << 0) != 0:
|
|
||||||
print("left click")
|
|
||||||
clicked_cell = menu_grid.which_cell_contains((mouse_tg.x, mouse_tg.y))
|
|
||||||
if clicked_cell is not None:
|
|
||||||
index = (clicked_cell[1] * config["width"] + clicked_cell[0]) + (cur_page * page_size)
|
|
||||||
|
|
||||||
if right_tg.contains((mouse_tg.x, mouse_tg.y, 0)):
|
|
||||||
page_right()
|
|
||||||
if left_tg.contains((mouse_tg.x, mouse_tg.y, 0)):
|
|
||||||
page_left()
|
|
||||||
|
|
||||||
|
clicked_coords = (mouse.x, mouse.y, 0)
|
||||||
|
if left_tg.contains(clicked_coords):
|
||||||
|
if cur_page > 0:
|
||||||
|
cur_page -= 1
|
||||||
|
display_page(cur_page)
|
||||||
|
elif right_tg.contains(clicked_coords):
|
||||||
|
if cur_page < math.ceil(len(apps) / 6) - 1:
|
||||||
|
cur_page += 1
|
||||||
|
display_page(cur_page)
|
||||||
|
|
||||||
if index is not None:
|
if index is not None:
|
||||||
print("index", index)
|
print("index", index)
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 918 B After Width: | Height: | Size: 918 B |
Binary file not shown.
|
Before Width: | Height: | Size: 918 B After Width: | Height: | Size: 918 B |
|
|
@ -1 +0,0 @@
|
||||||
CIRCUITPY_PYSTACK_SIZE=4000
|
|
||||||
Loading…
Reference in a new issue