././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1731159498.3002899
adventure-1.7/ 0000775 0001750 0001750 00000000000 14713662712 013261 5 ustar 00brandon brandon ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1573219777.0
adventure-1.7/LICENSE.ASF-2 0000640 0001750 0001750 00000026136 13561266701 015035 0 ustar 00brandon brandon
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1731159498.3002899
adventure-1.7/PKG-INFO 0000644 0001750 0001750 00000016033 14713662712 014357 0 ustar 00brandon brandon Metadata-Version: 2.1
Name: adventure
Version: 1.7
Summary: Colossal Cave adventure game at the Python prompt
Home-page: https://github.com/brandon-rhodes/python-adventure
Author: Brandon Craig Rhodes
Author-email: brandon@rhodesmill.org
Classifier: Development Status :: 6 - Mature
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.2
Classifier: Topic :: Games/Entertainment
License-File: LICENSE.ASF-2
This is a faithful port of the “Adventure” game to Python 3 from the
original 1977 FORTRAN code by Crowther and Woods (it is driven by the
same ``advent.dat`` file!) that lets you explore Colossal Cave, where
others have found fortunes in treasure and gold, though it is rumored
that some who enter are never seen again.
You can run the game right at your command line if you have `uv
`_ installed::
uvx adventure
This page:
http://rickadams.org/adventure/e_downloads.html
offers the original PHP source code at this link:
http://www.ifarchive.org/if-archive/games/source/advent-original.tar.gz
To encourage the use of Python 3, the game is designed to be played
right at the Python prompt. Single-word commands can be typed by
themselves, but two-word commands should be written as a function call
(since a two-word command would not be valid Python)::
>>> import adventure
>>> adventure.play()
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
>>> no
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.
>>> east
YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
THERE ARE SOME KEYS ON THE GROUND HERE.
THERE IS A SHINY BRASS LAMP NEARBY.
THERE IS FOOD HERE.
THERE IS A BOTTLE OF WATER HERE.
>>> get(lamp)
OK
>>> leave
YOU'RE AT END OF ROAD AGAIN.
>>> south
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
The original Adventure paid attention to only the first five letters of
each command, so a long command like ``inventory`` could simply be typed
as ``inven``. This package defines a symbol for both versions of every
long word, so you can type the long or short version as you please.
You can save your game at any time by calling the ``save()`` command
with a filename, and then can resume it later::
>>> save('advent.save')
GAME SAVED
>>> adventure.resume('advent.save')
GAME RESTORED
>>> look
SORRY, BUT I AM NOT ALLOWED TO GIVE MORE DETAIL. I WILL REPEAT THE
LONG DESCRIPTION OF YOUR LOCATION.
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
You can find two complete, working walkthroughs of the game in its
``tests`` directory, which you can run using the ``discover`` module that
comes built-in with Python 3::
$ python3 -m unittest discover adventure
I wrote most of this package over Christmas vacation 2010, to learn more
about the workings of the game that so enthralled me as a child; the
project also gave me practice writing Python 3. I still forget the
parentheses when writing ``print()`` if I am not paying attention.
Traditional Mode
================
You can also use this package to play Adventure at a traditional prompt
that does not require its input to be valid Python. Use your operating
system command line to run the package::
$ python3 -m adventure
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
>
At the prompt that will appear, two-word commands can simply be
separated by a space::
> get lamp
OK
For extra authenticity, the output of the Adventure game in this mode is
typed to your screen at 1200 baud. You will note that although this
prints the text faster than you can read it anyway, your experience of
the game will improve considerably, especially when a move results in a
surprise.
Why is the game better at 1200 baud? When a paragraph of text is
allowed to appear on the screen all at once, your eyes scan the entire
paragraph for important information, often ruining any surprises before
you can then settle down and read it from the beginning. But at 1200
baud, you wind up reading the text in order as it appears, which unfolds
the narrative sequentially as the author of Adventure intended.
If you created a file with the in-game ``save`` command, you can restore
it later by naming it on the command line::
> save mygame
GAME SAVED
> quit
DO YOU REALLY WANT TO QUIT NOW?
> y
OK
$ python3 -m adventure mygame
GAME RESTORED
>
Notes
=====
* Several Adventure commands conflict with standard Python built-in
functions. If you want to run the normal Python function ``exit()``,
``open()``, ``quit()``, or ``help()``, then import the ``builtin``
module and run the copy of the function stored there.
* The word “break” is a Python keyword, so there was no possibility of
using it in the game. Instead, use one of the two synonyms defined by
the PDP version of Adventure: “shatter” or “smash.”
Copyright
=========
The ``advent.dat`` game data file distributed with this Python package,
like the rest of the original source code for Adventure, is a public
domain work. Phrases from the original work that have been copied into
my source code from the FORTRAN source (the famous phrase “You have
gotten yourself killed” and so forth) remain public domain and can be
used without attribution.
My own Python code that re-implements the game engine is:
Copyright 2010–2015 Brandon Rhodes
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Changelog
=========
| 1.7 — 2024 November 9 — add an ``adventure`` console script so this package can be run with ``uvx adventure``.
| 1.6 — 2020 August 15 — add support for upper-case commands typed at the terminal; and fix exception if user dies with water in their bottle `(see #26) `_.
| 1.5 — 2020 July 18 — fix for fatal exception when “lamp turn” is entered.
| 1.4 — 2016 January 31 — readline editing; added license; bug fix; test fix.
| 1.3 — 2012 April 27 — installs on Windows; fixed undefined commands
| 1.2 — 2012 April 5 — restoring saves from command line; 5-letter commands
| 1.1 — 2011 March 12 — traditional mode; more flexible Python syntax
| 1.0 — 2011 February 15 — 100% test coverage, feature-complete
| 0.3 — 2011 January 31 — first public release
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1573219777.0
adventure-1.7/README.md 0000640 0001750 0001750 00000000272 13561266701 014531 0 ustar 00brandon brandon Welcome to the git repository for the Python 3 version of Adventure!
The project README is one level deeper, inside of the package itself:
[adventure/README.txt](adventure/README.txt)
././@PaxHeader 0000000 0000000 0000000 00000000032 00000000000 010210 x ustar 00 26 mtime=1731159498.29629
adventure-1.7/adventure/ 0000775 0001750 0001750 00000000000 14713662712 015256 5 ustar 00brandon brandon ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1731158880.0
adventure-1.7/adventure/README.txt 0000664 0001750 0001750 00000014703 14713661540 016757 0 ustar 00brandon brandon This is a faithful port of the “Adventure” game to Python 3 from the
original 1977 FORTRAN code by Crowther and Woods (it is driven by the
same ``advent.dat`` file!) that lets you explore Colossal Cave, where
others have found fortunes in treasure and gold, though it is rumored
that some who enter are never seen again.
You can run the game right at your command line if you have `uv
`_ installed::
uvx adventure
This page:
http://rickadams.org/adventure/e_downloads.html
offers the original PHP source code at this link:
http://www.ifarchive.org/if-archive/games/source/advent-original.tar.gz
To encourage the use of Python 3, the game is designed to be played
right at the Python prompt. Single-word commands can be typed by
themselves, but two-word commands should be written as a function call
(since a two-word command would not be valid Python)::
>>> import adventure
>>> adventure.play()
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
>>> no
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.
>>> east
YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
THERE ARE SOME KEYS ON THE GROUND HERE.
THERE IS A SHINY BRASS LAMP NEARBY.
THERE IS FOOD HERE.
THERE IS A BOTTLE OF WATER HERE.
>>> get(lamp)
OK
>>> leave
YOU'RE AT END OF ROAD AGAIN.
>>> south
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
The original Adventure paid attention to only the first five letters of
each command, so a long command like ``inventory`` could simply be typed
as ``inven``. This package defines a symbol for both versions of every
long word, so you can type the long or short version as you please.
You can save your game at any time by calling the ``save()`` command
with a filename, and then can resume it later::
>>> save('advent.save')
GAME SAVED
>>> adventure.resume('advent.save')
GAME RESTORED
>>> look
SORRY, BUT I AM NOT ALLOWED TO GIVE MORE DETAIL. I WILL REPEAT THE
LONG DESCRIPTION OF YOUR LOCATION.
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
You can find two complete, working walkthroughs of the game in its
``tests`` directory, which you can run using the ``discover`` module that
comes built-in with Python 3::
$ python3 -m unittest discover adventure
I wrote most of this package over Christmas vacation 2010, to learn more
about the workings of the game that so enthralled me as a child; the
project also gave me practice writing Python 3. I still forget the
parentheses when writing ``print()`` if I am not paying attention.
Traditional Mode
================
You can also use this package to play Adventure at a traditional prompt
that does not require its input to be valid Python. Use your operating
system command line to run the package::
$ python3 -m adventure
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
>
At the prompt that will appear, two-word commands can simply be
separated by a space::
> get lamp
OK
For extra authenticity, the output of the Adventure game in this mode is
typed to your screen at 1200 baud. You will note that although this
prints the text faster than you can read it anyway, your experience of
the game will improve considerably, especially when a move results in a
surprise.
Why is the game better at 1200 baud? When a paragraph of text is
allowed to appear on the screen all at once, your eyes scan the entire
paragraph for important information, often ruining any surprises before
you can then settle down and read it from the beginning. But at 1200
baud, you wind up reading the text in order as it appears, which unfolds
the narrative sequentially as the author of Adventure intended.
If you created a file with the in-game ``save`` command, you can restore
it later by naming it on the command line::
> save mygame
GAME SAVED
> quit
DO YOU REALLY WANT TO QUIT NOW?
> y
OK
$ python3 -m adventure mygame
GAME RESTORED
>
Notes
=====
* Several Adventure commands conflict with standard Python built-in
functions. If you want to run the normal Python function ``exit()``,
``open()``, ``quit()``, or ``help()``, then import the ``builtin``
module and run the copy of the function stored there.
* The word “break” is a Python keyword, so there was no possibility of
using it in the game. Instead, use one of the two synonyms defined by
the PDP version of Adventure: “shatter” or “smash.”
Copyright
=========
The ``advent.dat`` game data file distributed with this Python package,
like the rest of the original source code for Adventure, is a public
domain work. Phrases from the original work that have been copied into
my source code from the FORTRAN source (the famous phrase “You have
gotten yourself killed” and so forth) remain public domain and can be
used without attribution.
My own Python code that re-implements the game engine is:
Copyright 2010–2015 Brandon Rhodes
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Changelog
=========
| 1.7 — 2024 November 9 — add an ``adventure`` console script so this package can be run with ``uvx adventure``.
| 1.6 — 2020 August 15 — add support for upper-case commands typed at the terminal; and fix exception if user dies with water in their bottle `(see #26) `_.
| 1.5 — 2020 July 18 — fix for fatal exception when “lamp turn” is entered.
| 1.4 — 2016 January 31 — readline editing; added license; bug fix; test fix.
| 1.3 — 2012 April 27 — installs on Windows; fixed undefined commands
| 1.2 — 2012 April 5 — restoring saves from command line; 5-letter commands
| 1.1 — 2011 March 12 — traditional mode; more flexible Python syntax
| 1.0 — 2011 February 15 — 100% test coverage, feature-complete
| 0.3 — 2011 January 31 — first public release
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1573220109.0
adventure-1.7/adventure/__init__.py 0000640 0001750 0001750 00000002225 13561267415 017363 0 ustar 00brandon brandon """The Adventure game.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
import sys
if sys.version_info <= (3,):
raise RuntimeError('Alas, Adventure requires Python 3 or later')
def load_advent_dat(data):
import os
from .data import parse
datapath = os.path.join(os.path.dirname(__file__), 'advent.dat')
with open(datapath, 'r', encoding='ascii') as datafile:
parse(data, datafile)
def play(seed=None):
"""Turn the Python prompt into an Adventure game.
With optional the `seed` argument the caller can supply an integer
to start the Python random number generator at a known state.
"""
global _game
from .game import Game
from .prompt import install_words
_game = Game(seed)
load_advent_dat(_game)
install_words(_game)
_game.start()
print(_game.output[:-1])
def resume(savefile, quiet=False):
global _game
from .game import Game
from .prompt import install_words
_game = Game.resume(savefile)
install_words(_game)
if not quiet:
print('GAME RESTORED\n')
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1731157505.0
adventure-1.7/adventure/__main__.py 0000640 0001750 0001750 00000002506 14713657001 017340 0 ustar 00brandon brandon """Offer Adventure at a custom command prompt.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
import argparse
import os
import re
import readline
import sys
from time import sleep
from . import load_advent_dat
from .game import Game
BAUD = 1200
def baudout(s):
out = sys.stdout
for c in s:
sleep(9. / BAUD) # 8 bits + 1 stop bit @ the given baud rate
out.write(c)
out.flush()
def loop(args):
parser = argparse.ArgumentParser(
description='Adventure into the Colossal Caves.',
prog='{} -m adventure'.format(os.path.basename(sys.executable)))
parser.add_argument(
'savefile', nargs='?', help='The filename of game you have saved.')
args = parser.parse_args(args)
if args.savefile is None:
game = Game()
load_advent_dat(game)
game.start()
baudout(game.output)
else:
game = Game.resume(args.savefile)
baudout('GAME RESTORED\n')
while not game.is_finished:
line = input('> ').lower()
words = re.findall(r'\w+', line)
if words:
baudout(game.do_command(words))
def main():
try:
loop(sys.argv[1:])
except EOFError:
pass
if __name__ == '__main__':
main()
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1573219777.0
adventure-1.7/adventure/advent.dat 0000640 0001750 0001750 00000154237 13561266701 017235 0 ustar 00brandon brandon 1
1 YOU ARE STANDING AT THE END OF A ROAD BEFORE A SMALL BRICK BUILDING.
1 AROUND YOU IS A FOREST. A SMALL STREAM FLOWS OUT OF THE BUILDING AND
1 DOWN A GULLY.
2 YOU HAVE WALKED UP A HILL, STILL IN THE FOREST. THE ROAD SLOPES BACK
2 DOWN THE OTHER SIDE OF THE HILL. THERE IS A BUILDING IN THE DISTANCE.
3 YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
4 YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
4 ROCKY BED.
5 YOU ARE IN OPEN FOREST, WITH A DEEP VALLEY TO ONE SIDE.
6 YOU ARE IN OPEN FOREST NEAR BOTH A VALLEY AND A ROAD.
7 AT YOUR FEET ALL THE WATER OF THE STREAM SPLASHES INTO A 2-INCH SLIT
7 IN THE ROCK. DOWNSTREAM THE STREAMBED IS BARE ROCK.
8 YOU ARE IN A 20-FOOT DEPRESSION FLOORED WITH BARE DIRT. SET INTO THE
8 DIRT IS A STRONG STEEL GRATE MOUNTED IN CONCRETE. A DRY STREAMBED
8 LEADS INTO THE DEPRESSION.
9 YOU ARE IN A SMALL CHAMBER BENEATH A 3X3 STEEL GRATE TO THE SURFACE.
9 A LOW CRAWL OVER COBBLES LEADS INWARD TO THE WEST.
10 YOU ARE CRAWLING OVER COBBLES IN A LOW PASSAGE. THERE IS A DIM LIGHT
10 AT THE EAST END OF THE PASSAGE.
11 YOU ARE IN A DEBRIS ROOM FILLED WITH STUFF WASHED IN FROM THE SURFACE.
11 A LOW WIDE PASSAGE WITH COBBLES BECOMES PLUGGED WITH MUD AND DEBRIS
11 HERE, BUT AN AWKWARD CANYON LEADS UPWARD AND WEST. A NOTE ON THE WALL
11 SAYS "MAGIC WORD XYZZY".
12 YOU ARE IN AN AWKWARD SLOPING EAST/WEST CANYON.
13 YOU ARE IN A SPLENDID CHAMBER THIRTY FEET HIGH. THE WALLS ARE FROZEN
13 RIVERS OF ORANGE STONE. AN AWKWARD CANYON AND A GOOD PASSAGE EXIT
13 FROM EAST AND WEST SIDES OF THE CHAMBER.
14 AT YOUR FEET IS A SMALL PIT BREATHING TRACES OF WHITE MIST. AN EAST
14 PASSAGE ENDS HERE EXCEPT FOR A SMALL CRACK LEADING ON.
15 YOU ARE AT ONE END OF A VAST HALL STRETCHING FORWARD OUT OF SIGHT TO
15 THE WEST. THERE ARE OPENINGS TO EITHER SIDE. NEARBY, A WIDE STONE
15 STAIRCASE LEADS DOWNWARD. THE HALL IS FILLED WITH WISPS OF WHITE MIST
15 SWAYING TO AND FRO ALMOST AS IF ALIVE. A COLD WIND BLOWS UP THE
15 STAIRCASE. THERE IS A PASSAGE AT THE TOP OF A DOME BEHIND YOU.
16 THE CRACK IS FAR TOO SMALL FOR YOU TO FOLLOW.
17 YOU ARE ON THE EAST BANK OF A FISSURE SLICING CLEAR ACROSS THE HALL.
17 THE MIST IS QUITE THICK HERE, AND THE FISSURE IS TOO WIDE TO JUMP.
18 THIS IS A LOW ROOM WITH A CRUDE NOTE ON THE WALL. THE NOTE SAYS,
18 "YOU WON'T GET IT UP THE STEPS".
19 YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
19 DIRECTIONS.
20 YOU ARE AT THE BOTTOM OF THE PIT WITH A BROKEN NECK.
21 YOU DIDN'T MAKE IT.
22 THE DOME IS UNCLIMBABLE.
23 YOU ARE AT THE WEST END OF THE TWOPIT ROOM. THERE IS A LARGE HOLE IN
23 THE WALL ABOVE THE PIT AT THIS END OF THE ROOM.
24 YOU ARE AT THE BOTTOM OF THE EASTERN PIT IN THE TWOPIT ROOM. THERE IS
24 A SMALL POOL OF OIL IN ONE CORNER OF THE PIT.
25 YOU ARE AT THE BOTTOM OF THE WESTERN PIT IN THE TWOPIT ROOM. THERE IS
25 A LARGE HOLE IN THE WALL ABOUT 25 FEET ABOVE YOU.
26 YOU CLAMBER UP THE PLANT AND SCURRY THROUGH THE HOLE AT THE TOP.
27 YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
28 YOU ARE IN A LOW N/S PASSAGE AT A HOLE IN THE FLOOR. THE HOLE GOES
28 DOWN TO AN E/W PASSAGE.
29 YOU ARE IN THE SOUTH SIDE CHAMBER.
30 YOU ARE IN THE WEST SIDE CHAMBER OF THE HALL OF THE MOUNTAIN KING.
30 A PASSAGE CONTINUES WEST AND UP HERE.
31 >$<
32 YOU CAN'T GET BY THE SNAKE.
33 YOU ARE IN A LARGE ROOM, WITH A PASSAGE TO THE SOUTH, A PASSAGE TO THE
33 WEST, AND A WALL OF BROKEN ROCK TO THE EAST. THERE IS A LARGE "Y2" ON
33 A ROCK IN THE ROOM'S CENTER.
34 YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
35 YOU'RE AT A LOW WINDOW OVERLOOKING A HUGE PIT, WHICH EXTENDS UP OUT OF
35 SIGHT. A FLOOR IS INDISTINCTLY VISIBLE OVER 50 FEET BELOW. TRACES OF
35 WHITE MIST COVER THE FLOOR OF THE PIT, BECOMING THICKER TO THE RIGHT.
35 MARKS IN THE DUST AROUND THE WINDOW WOULD SEEM TO INDICATE THAT
35 SOMEONE HAS BEEN HERE RECENTLY. DIRECTLY ACROSS THE PIT FROM YOU AND
35 25 FEET AWAY THERE IS A SIMILAR WINDOW LOOKING INTO A LIGHTED ROOM. A
35 SHADOWY FIGURE CAN BE SEEN THERE PEERING BACK AT YOU.
36 YOU ARE IN A DIRTY BROKEN PASSAGE. TO THE EAST IS A CRAWL. TO THE
36 WEST IS A LARGE PASSAGE. ABOVE YOU IS A HOLE TO ANOTHER PASSAGE.
37 YOU ARE ON THE BRINK OF A SMALL CLEAN CLIMBABLE PIT. A CRAWL LEADS
37 WEST.
38 YOU ARE IN THE BOTTOM OF A SMALL PIT WITH A LITTLE STREAM, WHICH
38 ENTERS AND EXITS THROUGH TINY SLITS.
39 YOU ARE IN A LARGE ROOM FULL OF DUSTY ROCKS. THERE IS A BIG HOLE IN
39 THE FLOOR. THERE ARE CRACKS EVERYWHERE, AND A PASSAGE LEADING EAST.
40 YOU HAVE CRAWLED THROUGH A VERY LOW WIDE PASSAGE PARALLEL TO AND NORTH
40 OF THE HALL OF MISTS.
41 YOU ARE AT THE WEST END OF HALL OF MISTS. A LOW WIDE CRAWL CONTINUES
41 WEST AND ANOTHER GOES NORTH. TO THE SOUTH IS A LITTLE PASSAGE 6 FEET
41 OFF THE FLOOR.
42 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
43 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
44 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
45 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
46 DEAD END
47 DEAD END
48 DEAD END
49 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
50 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
51 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
52 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
53 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
54 DEAD END
55 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
56 DEAD END
57 YOU ARE ON THE BRINK OF A THIRTY FOOT PIT WITH A MASSIVE ORANGE COLUMN
57 DOWN ONE WALL. YOU COULD CLIMB DOWN HERE BUT YOU COULD NOT GET BACK
57 UP. THE MAZE CONTINUES AT THIS LEVEL.
58 DEAD END
59 YOU HAVE CRAWLED THROUGH A VERY LOW WIDE PASSAGE PARALLEL TO AND NORTH
59 OF THE HALL OF MISTS.
60 YOU ARE AT THE EAST END OF A VERY LONG HALL APPARENTLY WITHOUT SIDE
60 CHAMBERS. TO THE EAST A LOW WIDE CRAWL SLANTS UP. TO THE NORTH A
60 ROUND TWO FOOT HOLE SLANTS DOWN.
61 YOU ARE AT THE WEST END OF A VERY LONG FEATURELESS HALL. THE HALL
61 JOINS UP WITH A NARROW NORTH/SOUTH PASSAGE.
62 YOU ARE AT A CROSSOVER OF A HIGH N/S PASSAGE AND A LOW E/W ONE.
63 DEAD END
64 YOU ARE AT A COMPLEX JUNCTION. A LOW HANDS AND KNEES PASSAGE FROM THE
64 NORTH JOINS A HIGHER CRAWL FROM THE EAST TO MAKE A WALKING PASSAGE
64 GOING WEST. THERE IS ALSO A LARGE ROOM ABOVE. THE AIR IS DAMP HERE.
65 YOU ARE IN BEDQUILT, A LONG EAST/WEST PASSAGE WITH HOLES EVERYWHERE.
65 TO EXPLORE AT RANDOM SELECT NORTH, SOUTH, UP, OR DOWN.
66 YOU ARE IN A ROOM WHOSE WALLS RESEMBLE SWISS CHEESE. OBVIOUS PASSAGES
66 GO WEST, EAST, NE, AND NW. PART OF THE ROOM IS OCCUPIED BY A LARGE
66 BEDROCK BLOCK.
67 YOU ARE AT THE EAST END OF THE TWOPIT ROOM. THE FLOOR HERE IS
67 LITTERED WITH THIN ROCK SLABS, WHICH MAKE IT EASY TO DESCEND THE PITS.
67 THERE IS A PATH HERE BYPASSING THE PITS TO CONNECT PASSAGES FROM EAST
67 AND WEST. THERE ARE HOLES ALL OVER, BUT THE ONLY BIG ONE IS ON THE
67 WALL DIRECTLY OVER THE WEST PIT WHERE YOU CAN'T GET TO IT.
68 YOU ARE IN A LARGE LOW CIRCULAR CHAMBER WHOSE FLOOR IS AN IMMENSE SLAB
68 FALLEN FROM THE CEILING (SLAB ROOM). EAST AND WEST THERE ONCE WERE
68 LARGE PASSAGES, BUT THEY ARE NOW FILLED WITH BOULDERS. LOW SMALL
68 PASSAGES GO NORTH AND SOUTH, AND THE SOUTH ONE QUICKLY BENDS WEST
68 AROUND THE BOULDERS.
69 YOU ARE IN A SECRET N/S CANYON ABOVE A LARGE ROOM.
70 YOU ARE IN A SECRET N/S CANYON ABOVE A SIZABLE PASSAGE.
71 YOU ARE IN A SECRET CANYON AT A JUNCTION OF THREE CANYONS, BEARING
71 NORTH, SOUTH, AND SE. THE NORTH ONE IS AS TALL AS THE OTHER TWO
71 COMBINED.
72 YOU ARE IN A LARGE LOW ROOM. CRAWLS LEAD NORTH, SE, AND SW.
73 DEAD END CRAWL.
74 YOU ARE IN A SECRET CANYON WHICH HERE RUNS E/W. IT CROSSES OVER A
74 VERY TIGHT CANYON 15 FEET BELOW. IF YOU GO DOWN YOU MAY NOT BE ABLE
74 TO GET BACK UP.
75 YOU ARE AT A WIDE PLACE IN A VERY TIGHT N/S CANYON.
76 THE CANYON HERE BECOMES TOO TIGHT TO GO FURTHER SOUTH.
77 YOU ARE IN A TALL E/W CANYON. A LOW TIGHT CRAWL GOES 3 FEET NORTH AND
77 SEEMS TO OPEN UP.
78 THE CANYON RUNS INTO A MASS OF BOULDERS -- DEAD END.
79 THE STREAM FLOWS OUT THROUGH A PAIR OF 1 FOOT DIAMETER SEWER PIPES.
79 IT WOULD BE ADVISABLE TO USE THE EXIT.
80 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
81 DEAD END
82 DEAD END
83 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
84 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
85 DEAD END
86 DEAD END
87 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
88 YOU ARE IN A LONG, NARROW CORRIDOR STRETCHING OUT OF SIGHT TO THE
88 WEST. AT THE EASTERN END IS A HOLE THROUGH WHICH YOU CAN SEE A
88 PROFUSION OF LEAVES.
89 THERE IS NOTHING HERE TO CLIMB. USE "UP" OR "OUT" TO LEAVE THE PIT.
90 YOU HAVE CLIMBED UP THE PLANT AND OUT OF THE PIT.
91 YOU ARE AT THE TOP OF A STEEP INCLINE ABOVE A LARGE ROOM. YOU COULD
91 CLIMB DOWN HERE, BUT YOU WOULD NOT BE ABLE TO CLIMB UP. THERE IS A
91 PASSAGE LEADING BACK TO THE NORTH.
92 YOU ARE IN THE GIANT ROOM. THE CEILING HERE IS TOO HIGH UP FOR YOUR
92 LAMP TO SHOW IT. CAVERNOUS PASSAGES LEAD EAST, NORTH, AND SOUTH. ON
92 THE WEST WALL IS SCRAWLED THE INSCRIPTION, "FEE FIE FOE FOO" [SIC].
93 THE PASSAGE HERE IS BLOCKED BY A RECENT CAVE-IN.
94 YOU ARE AT ONE END OF AN IMMENSE NORTH/SOUTH PASSAGE.
95 YOU ARE IN A MAGNIFICENT CAVERN WITH A RUSHING STREAM, WHICH CASCADES
95 OVER A SPARKLING WATERFALL INTO A ROARING WHIRLPOOL WHICH DISAPPEARS
95 THROUGH A HOLE IN THE FLOOR. PASSAGES EXIT TO THE SOUTH AND WEST.
96 YOU ARE IN THE SOFT ROOM. THE WALLS ARE COVERED WITH HEAVY CURTAINS,
96 THE FLOOR WITH A THICK PILE CARPET. MOSS COVERS THE CEILING.
97 THIS IS THE ORIENTAL ROOM. ANCIENT ORIENTAL CAVE DRAWINGS COVER THE
97 WALLS. A GENTLY SLOPING PASSAGE LEADS UPWARD TO THE NORTH, ANOTHER
97 PASSAGE LEADS SE, AND A HANDS AND KNEES CRAWL LEADS WEST.
98 YOU ARE FOLLOWING A WIDE PATH AROUND THE OUTER EDGE OF A LARGE CAVERN.
98 FAR BELOW, THROUGH A HEAVY WHITE MIST, STRANGE SPLASHING NOISES CAN BE
98 HEARD. THE MIST RISES UP THROUGH A FISSURE IN THE CEILING. THE PATH
98 EXITS TO THE SOUTH AND WEST.
99 YOU ARE IN AN ALCOVE. A SMALL NW PATH SEEMS TO WIDEN AFTER A SHORT
99 DISTANCE. AN EXTREMELY TIGHT TUNNEL LEADS EAST. IT LOOKS LIKE A VERY
99 TIGHT SQUEEZE. AN EERIE LIGHT CAN BE SEEN AT THE OTHER END.
100 YOU'RE IN A SMALL CHAMBER LIT BY AN EERIE GREEN LIGHT. AN EXTREMELY
100 NARROW TUNNEL EXITS TO THE WEST. A DARK CORRIDOR LEADS NE.
101 YOU'RE IN THE DARK-ROOM. A CORRIDOR LEADING SOUTH IS THE ONLY EXIT.
102 YOU ARE IN AN ARCHED HALL. A CORAL PASSAGE ONCE CONTINUED UP AND EAST
102 FROM HERE, BUT IS NOW BLOCKED BY DEBRIS. THE AIR SMELLS OF SEA WATER.
103 YOU'RE IN A LARGE ROOM CARVED OUT OF SEDIMENTARY ROCK. THE FLOOR AND
103 WALLS ARE LITTERED WITH BITS OF SHELLS IMBEDDED IN THE STONE. A
103 SHALLOW PASSAGE PROCEEDS DOWNWARD, AND A SOMEWHAT STEEPER ONE LEADS
103 UP. A LOW HANDS AND KNEES PASSAGE ENTERS FROM THE SOUTH.
104 YOU ARE IN A LONG SLOPING CORRIDOR WITH RAGGED SHARP WALLS.
105 YOU ARE IN A CUL-DE-SAC ABOUT EIGHT FEET ACROSS.
106 YOU ARE IN AN ANTEROOM LEADING TO A LARGE PASSAGE TO THE EAST. SMALL
106 PASSAGES GO WEST AND UP. THE REMNANTS OF RECENT DIGGING ARE EVIDENT.
106 A SIGN IN MIDAIR HERE SAYS "CAVE UNDER CONSTRUCTION BEYOND THIS POINT.
106 PROCEED AT OWN RISK. [WITT CONSTRUCTION COMPANY]"
107 YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL DIFFERENT.
108 YOU ARE AT WITT'S END. PASSAGES LEAD OFF IN *ALL* DIRECTIONS.
109 YOU ARE IN A NORTH/SOUTH CANYON ABOUT 25 FEET ACROSS. THE FLOOR IS
109 COVERED BY WHITE MIST SEEPING IN FROM THE NORTH. THE WALLS EXTEND
109 UPWARD FOR WELL OVER 100 FEET. SUSPENDED FROM SOME UNSEEN POINT FAR
109 ABOVE YOU, AN ENORMOUS TWO-SIDED MIRROR IS HANGING PARALLEL TO AND
109 MIDWAY BETWEEN THE CANYON WALLS. (THE MIRROR IS OBVIOUSLY PROVIDED
109 FOR THE USE OF THE DWARVES, WHO AS YOU KNOW, ARE EXTREMELY VAIN.) A
109 SMALL WINDOW CAN BE SEEN IN EITHER WALL, SOME FIFTY FEET UP.
110 YOU'RE AT A LOW WINDOW OVERLOOKING A HUGE PIT, WHICH EXTENDS UP OUT OF
110 SIGHT. A FLOOR IS INDISTINCTLY VISIBLE OVER 50 FEET BELOW. TRACES OF
110 WHITE MIST COVER THE FLOOR OF THE PIT, BECOMING THICKER TO THE LEFT.
110 MARKS IN THE DUST AROUND THE WINDOW WOULD SEEM TO INDICATE THAT
110 SOMEONE HAS BEEN HERE RECENTLY. DIRECTLY ACROSS THE PIT FROM YOU AND
110 25 FEET AWAY THERE IS A SIMILAR WINDOW LOOKING INTO A LIGHTED ROOM. A
110 SHADOWY FIGURE CAN BE SEEN THERE PEERING BACK AT YOU.
111 A LARGE STALACTITE EXTENDS FROM THE ROOF AND ALMOST REACHES THE FLOOR
111 BELOW. YOU COULD CLIMB DOWN IT, AND JUMP FROM IT TO THE FLOOR, BUT
111 HAVING DONE SO YOU WOULD BE UNABLE TO REACH IT TO CLIMB BACK UP.
112 YOU ARE IN A LITTLE MAZE OF TWISTING PASSAGES, ALL DIFFERENT.
113 YOU ARE AT THE EDGE OF A LARGE UNDERGROUND RESERVOIR. AN OPAQUE CLOUD
113 OF WHITE MIST FILLS THE ROOM AND RISES RAPIDLY UPWARD. THE LAKE IS
113 FED BY A STREAM, WHICH TUMBLES OUT OF A HOLE IN THE WALL ABOUT 10 FEET
113 OVERHEAD AND SPLASHES NOISILY INTO THE WATER SOMEWHERE WITHIN THE
113 MIST. THE ONLY PASSAGE GOES BACK TOWARD THE SOUTH.
114 DEAD END
115 YOU ARE AT THE NORTHEAST END OF AN IMMENSE ROOM, EVEN LARGER THAN THE
115 GIANT ROOM. IT APPEARS TO BE A REPOSITORY FOR THE "ADVENTURE"
115 PROGRAM. MASSIVE TORCHES FAR OVERHEAD BATHE THE ROOM WITH SMOKY
115 YELLOW LIGHT. SCATTERED ABOUT YOU CAN BE SEEN A PILE OF BOTTLES (ALL
115 OF THEM EMPTY), A NURSERY OF YOUNG BEANSTALKS MURMURING QUIETLY, A BED
115 OF OYSTERS, A BUNDLE OF BLACK RODS WITH RUSTY STARS ON THEIR ENDS, AND
115 A COLLECTION OF BRASS LANTERNS. OFF TO ONE SIDE A GREAT MANY DWARVES
115 ARE SLEEPING ON THE FLOOR, SNORING LOUDLY. A SIGN NEARBY READS: "DO
115 NOT DISTURB THE DWARVES!" AN IMMENSE MIRROR IS HANGING AGAINST ONE
115 WALL, AND STRETCHES TO THE OTHER END OF THE ROOM, WHERE VARIOUS OTHER
115 SUNDRY OBJECTS CAN BE GLIMPSED DIMLY IN THE DISTANCE.
116 YOU ARE AT THE SOUTHWEST END OF THE REPOSITORY. TO ONE SIDE IS A PIT
116 FULL OF FIERCE GREEN SNAKES. ON THE OTHER SIDE IS A ROW OF SMALL
116 WICKER CAGES, EACH OF WHICH CONTAINS A LITTLE SULKING BIRD. IN ONE
116 CORNER IS A BUNDLE OF BLACK RODS WITH RUSTY MARKS ON THEIR ENDS. A
116 LARGE NUMBER OF VELVET PILLOWS ARE SCATTERED ABOUT ON THE FLOOR. A
116 VAST MIRROR STRETCHES OFF TO THE NORTHEAST. AT YOUR FEET IS A LARGE
116 STEEL GRATE, NEXT TO WHICH IS A SIGN WHICH READS, "TREASURE VAULT.
116 KEYS IN MAIN OFFICE."
117 YOU ARE ON ONE SIDE OF A LARGE, DEEP CHASM. A HEAVY WHITE MIST RISING
117 UP FROM BELOW OBSCURES ALL VIEW OF THE FAR SIDE. A SW PATH LEADS AWAY
117 FROM THE CHASM INTO A WINDING CORRIDOR.
118 YOU ARE IN A LONG WINDING CORRIDOR SLOPING OUT OF SIGHT IN BOTH
118 DIRECTIONS.
119 YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
120 YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
121 YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
122 YOU ARE ON THE FAR SIDE OF THE CHASM. A NE PATH LEADS AWAY FROM THE
122 CHASM ON THIS SIDE.
123 YOU'RE IN A LONG EAST/WEST CORRIDOR. A FAINT RUMBLING NOISE CAN BE
123 HEARD IN THE DISTANCE.
124 THE PATH FORKS HERE. THE LEFT FORK LEADS NORTHEAST. A DULL RUMBLING
124 SEEMS TO GET LOUDER IN THAT DIRECTION. THE RIGHT FORK LEADS SOUTHEAST
124 DOWN A GENTLE SLOPE. THE MAIN CORRIDOR ENTERS FROM THE WEST.
125 THE WALLS ARE QUITE WARM HERE. FROM THE NORTH CAN BE HEARD A STEADY
125 ROAR, SO LOUD THAT THE ENTIRE CAVE SEEMS TO BE TREMBLING. ANOTHER
125 PASSAGE LEADS SOUTH, AND A LOW CRAWL GOES EAST.
126 YOU ARE ON THE EDGE OF A BREATH-TAKING VIEW. FAR BELOW YOU IS AN
126 ACTIVE VOLCANO, FROM WHICH GREAT GOUTS OF MOLTEN LAVA COME SURGING
126 OUT, CASCADING BACK DOWN INTO THE DEPTHS. THE GLOWING ROCK FILLS THE
126 FARTHEST REACHES OF THE CAVERN WITH A BLOOD-RED GLARE, GIVING EVERY-
126 THING AN EERIE, MACABRE APPEARANCE. THE AIR IS FILLED WITH FLICKERING
126 SPARKS OF ASH AND A HEAVY SMELL OF BRIMSTONE. THE WALLS ARE HOT TO
126 THE TOUCH, AND THE THUNDERING OF THE VOLCANO DROWNS OUT ALL OTHER
126 SOUNDS. EMBEDDED IN THE JAGGED ROOF FAR OVERHEAD ARE MYRIAD TWISTED
126 FORMATIONS COMPOSED OF PURE WHITE ALABASTER, WHICH SCATTER THE MURKY
126 LIGHT INTO SINISTER APPARITIONS UPON THE WALLS. TO ONE SIDE IS A DEEP
126 GORGE, FILLED WITH A BIZARRE CHAOS OF TORTURED ROCK WHICH SEEMS TO
126 HAVE BEEN CRAFTED BY THE DEVIL HIMSELF. AN IMMENSE RIVER OF FIRE
126 CRASHES OUT FROM THE DEPTHS OF THE VOLCANO, BURNS ITS WAY THROUGH THE
126 GORGE, AND PLUMMETS INTO A BOTTOMLESS PIT FAR OFF TO YOUR LEFT. TO
126 THE RIGHT, AN IMMENSE GEYSER OF BLISTERING STEAM ERUPTS CONTINUOUSLY
126 FROM A BARREN ISLAND IN THE CENTER OF A SULFUROUS LAKE, WHICH BUBBLES
126 OMINOUSLY. THE FAR RIGHT WALL IS AFLAME WITH AN INCANDESCENCE OF ITS
126 OWN, WHICH LENDS AN ADDITIONAL INFERNAL SPLENDOR TO THE ALREADY
126 HELLISH SCENE. A DARK, FOREBODING PASSAGE EXITS TO THE SOUTH.
127 YOU ARE IN A SMALL CHAMBER FILLED WITH LARGE BOULDERS. THE WALLS ARE
127 VERY WARM, CAUSING THE AIR IN THE ROOM TO BE ALMOST STIFLING FROM THE
127 HEAT. THE ONLY EXIT IS A CRAWL HEADING WEST, THROUGH WHICH IS COMING
127 A LOW RUMBLING.
128 YOU ARE WALKING ALONG A GENTLY SLOPING NORTH/SOUTH PASSAGE LINED WITH
128 ODDLY SHAPED LIMESTONE FORMATIONS.
129 YOU ARE STANDING AT THE ENTRANCE TO A LARGE, BARREN ROOM. A SIGN
129 POSTED ABOVE THE ENTRANCE READS: "CAUTION! BEAR IN ROOM!"
130 YOU ARE INSIDE A BARREN ROOM. THE CENTER OF THE ROOM IS COMPLETELY
130 EMPTY EXCEPT FOR SOME DUST. MARKS IN THE DUST LEAD AWAY TOWARD THE
130 FAR END OF THE ROOM. THE ONLY EXIT IS THE WAY YOU CAME IN.
131 YOU ARE IN A MAZE OF TWISTING LITTLE PASSAGES, ALL DIFFERENT.
132 YOU ARE IN A LITTLE MAZE OF TWISTY PASSAGES, ALL DIFFERENT.
133 YOU ARE IN A TWISTING MAZE OF LITTLE PASSAGES, ALL DIFFERENT.
134 YOU ARE IN A TWISTING LITTLE MAZE OF PASSAGES, ALL DIFFERENT.
135 YOU ARE IN A TWISTY LITTLE MAZE OF PASSAGES, ALL DIFFERENT.
136 YOU ARE IN A TWISTY MAZE OF LITTLE PASSAGES, ALL DIFFERENT.
137 YOU ARE IN A LITTLE TWISTY MAZE OF PASSAGES, ALL DIFFERENT.
138 YOU ARE IN A MAZE OF LITTLE TWISTING PASSAGES, ALL DIFFERENT.
139 YOU ARE IN A MAZE OF LITTLE TWISTY PASSAGES, ALL DIFFERENT.
140 DEAD END
-1 END
2
1 YOU'RE AT END OF ROAD AGAIN.
2 YOU'RE AT HILL IN ROAD.
3 YOU'RE INSIDE BUILDING.
4 YOU'RE IN VALLEY.
5 YOU'RE IN FOREST.
6 YOU'RE IN FOREST.
7 YOU'RE AT SLIT IN STREAMBED.
8 YOU'RE OUTSIDE GRATE.
9 YOU'RE BELOW THE GRATE.
10 YOU'RE IN COBBLE CRAWL.
11 YOU'RE IN DEBRIS ROOM.
13 YOU'RE IN BIRD CHAMBER.
14 YOU'RE AT TOP OF SMALL PIT.
15 YOU'RE IN HALL OF MISTS.
17 YOU'RE ON EAST BANK OF FISSURE.
18 YOU'RE IN NUGGET OF GOLD ROOM.
19 YOU'RE IN HALL OF MT KING
23 YOU'RE AT WEST END OF TWOPIT ROOM.
24 YOU'RE IN EAST PIT.
25 YOU'RE IN WEST PIT.
33 YOU'RE AT "Y2".
35 YOU'RE AT WINDOW ON PIT.
36 YOU'RE IN DIRTY PASSAGE.
39 YOU'RE IN DUSTY ROCK ROOM.
41 YOU'RE AT WEST END OF HALL OF MISTS.
57 YOU'RE AT BRINK OF PIT.
60 YOU'RE AT EAST END OF LONG HALL.
61 YOU'RE AT WEST END OF LONG HALL.
64 YOU'RE AT COMPLEX JUNCTION.
66 YOU'RE IN SWISS CHEESE ROOM.
67 YOU'RE AT EAST END OF TWOPIT ROOM.
68 YOU'RE IN SLAB ROOM.
71 YOU'RE AT JUNCTION OF THREE SECRET CANYONS.
74 YOU'RE IN SECRET E/W CANYON ABOVE TIGHT CANYON.
88 YOU'RE IN NARROW CORRIDOR.
91 YOU'RE AT STEEP INCLINE ABOVE LARGE ROOM.
92 YOU'RE IN GIANT ROOM.
95 YOU'RE IN CAVERN WITH WATERFALL.
96 YOU'RE IN SOFT ROOM.
97 YOU'RE IN ORIENTAL ROOM.
98 YOU'RE IN MISTY CAVERN.
99 YOU'RE IN ALCOVE.
100 YOU'RE IN PLOVER ROOM.
101 YOU'RE IN DARK-ROOM.
102 YOU'RE IN ARCHED HALL.
103 YOU'RE IN SHELL ROOM.
106 YOU'RE IN ANTEROOM.
108 YOU'RE AT WITT'S END.
109 YOU'RE IN MIRROR CANYON.
110 YOU'RE AT WINDOW ON PIT.
111 YOU'RE AT TOP OF STALACTITE.
113 YOU'RE AT RESERVOIR.
115 YOU'RE AT NE END.
116 YOU'RE AT SW END.
117 YOU'RE ON SW SIDE OF CHASM.
118 YOU'RE IN SLOPING CORRIDOR.
122 YOU'RE ON NE SIDE OF CHASM.
123 YOU'RE IN CORRIDOR.
124 YOU'RE AT FORK IN PATH.
125 YOU'RE AT JUNCTION WITH WARM WALLS.
126 YOU'RE AT BREATH-TAKING VIEW.
127 YOU'RE IN CHAMBER OF BOULDERS.
128 YOU'RE IN LIMESTONE PASSAGE.
129 YOU'RE IN FRONT OF BARREN ROOM.
130 YOU'RE IN BARREN ROOM.
-1
3
1 2 2 44 29
1 3 3 12 19 43
1 4 5 13 14 46 30
1 5 6 45 43
1 8 63
2 1 2 12 7 43 45 30
2 5 6 45 46
3 1 3 11 32 44
3 11 62
3 33 65
3 79 5 14
4 1 4 12 45
4 5 6 43 44 29
4 7 5 46 30
4 8 63
5 4 9 43 30
5 50005 6 7 45
5 6 6
5 5 44 46
6 1 2 45
6 4 9 43 44 30
6 5 6 46
7 1 12
7 4 4 45
7 5 6 43 44
7 8 5 15 16 46
7 595 60 14 30
8 5 6 43 44 46
8 1 12
8 7 4 13 45
8 303009 3 19 30
8 593 3
9 303008 11 29
9 593 11
9 10 17 18 19 44
9 14 31
9 11 51
10 9 11 20 21 43
10 11 19 22 44 51
10 14 31
11 303008 63
11 9 64
11 10 17 18 23 24 43
11 12 25 19 29 44
11 3 62
11 14 31
12 303008 63
12 9 64
12 11 30 43 51
12 13 19 29 44
12 14 31
13 303008 63
13 9 64
13 11 51
13 12 25 43
13 14 23 31 44
14 303008 63
14 9 64
14 11 51
14 13 23 43
14 150020 30 31 34
14 15 30
14 16 33 44
15 18 36 46
15 17 7 38 44
15 19 10 30 45
15 150022 29 31 34 35 23 43
15 14 29
15 34 55
16 14 1
17 15 38 43
17 312596 39
17 412021 7
17 412597 41 42 44 69
17 27 41
18 15 38 11 45
19 15 10 29 43
19 311028 45 36
19 311029 46 37
19 311030 44 7
19 32 45
19 35074 49
19 211032 49
19 74 66
20 0 1
21 0 1
22 15 1
23 67 43 42
23 68 44 61
23 25 30 31
23 648 52
24 67 29 11
25 23 29 11
25 724031 56
25 26 56
26 88 1
27 312596 39
27 412021 7
27 412597 41 42 43 69
27 17 41
27 40 45
27 41 44
28 19 38 11 46
28 33 45 55
28 36 30 52
29 19 38 11 45
30 19 38 11 43
30 62 44 29
31 524089 1
31 90 1
32 19 1
33 3 65
33 28 46
33 34 43 53 54
33 35 44
33 159302 71
33 100 71
34 33 30 55
34 15 29
35 33 43 55
35 20 39
36 37 43 17
36 28 29 52
36 39 44
36 65 70
37 36 44 17
37 38 30 31 56
38 37 56 29 11
38 595 60 14 30 4 5
39 36 43 23
39 64 30 52 58
39 65 70
40 41 1
41 42 46 29 23 56
41 27 43
41 59 45
41 60 44 17
42 41 29
42 42 45
42 43 43
42 45 46
42 80 44
43 42 44
43 44 46
43 45 43
44 43 43
44 48 30
44 50 46
44 82 45
45 42 44
45 43 45
45 46 43
45 47 46
45 87 29 30
46 45 44 11
47 45 43 11
48 44 29 11
49 50 43
49 51 44
50 44 43
50 49 44
50 51 30
50 52 46
51 49 44
51 50 29
51 52 43
51 53 46
52 50 44
52 51 43
52 52 46
52 53 29
52 55 45
52 86 30
53 51 44
53 52 45
53 54 46
54 53 44 11
55 52 44
55 55 45
55 56 30
55 57 43
56 55 29 11
57 13 30 56
57 55 44
57 58 46
57 83 45
57 84 43
58 57 43 11
59 27 1
60 41 43 29 17
60 61 44
60 62 45 30 52
61 60 43
61 62 45
61 100107 46
62 60 44
62 63 45
62 30 43
62 61 46
63 62 46 11
64 39 29 56 59
64 65 44 70
64 103 45 74
64 106 43
65 64 43
65 66 44
65 80556 46
65 68 61
65 80556 29
65 50070 29
65 39 29
65 60556 45
65 75072 45
65 71 45
65 80556 30
65 106 30
66 65 47
66 67 44
66 80556 46
66 77 25
66 96 43
66 50556 50
66 97 72
67 66 43
67 23 44 42
67 24 30 31
68 23 46
68 69 29 56
68 65 45
69 68 30 61
69 331120 46
69 119 46
69 109 45
69 113 75
70 71 45
70 65 30 23
70 111 46
71 65 48
71 70 46
71 110 45
72 65 70
72 118 49
72 73 45
72 97 48 72
73 72 46 17 11
74 19 43
74 331120 44
74 121 44
74 75 30
75 76 46
75 77 45
76 75 45
77 75 43
77 78 44
77 66 45 17
78 77 46
79 3 1
80 42 45
80 80 44
80 80 46
80 81 43
81 80 44 11
82 44 46 11
83 57 46
83 84 43
83 85 44
84 57 45
84 83 44
84 114 50
85 83 43 11
86 52 29 11
87 45 29 30
88 25 30 56 43
88 20 39
88 92 44 27
89 25 1
90 23 1
91 95 45 73 23
91 72 30 56
92 88 46
92 93 43
92 94 45
93 92 46 27 11
94 92 46 27 23
94 309095 45 3 73
94 611 45
95 94 46 11
95 92 27
95 91 44
96 66 44 11
97 66 48
97 72 44 17
97 98 29 45 73
98 97 46 72
98 99 44
99 98 50 73
99 301 43 23
99 100 43
100 301 44 23 11
100 99 44
100 159302 71
100 33 71
100 101 47 22
101 100 46 71 11
102 103 30 74 11
103 102 29 38
103 104 30
103 114618 46
103 115619 46
103 64 46
104 103 29 74
104 105 30
105 104 29 11
105 103 74
106 64 29
106 65 44
106 108 43
107 131 46
107 132 49
107 133 47
107 134 48
107 135 29
107 136 50
107 137 43
107 138 44
107 139 45
107 61 30
108 95556 43 45 46 47 48 49 50 29 30
108 106 43
108 626 44
109 69 46
109 113 45 75
110 71 44
110 20 39
111 70 45
111 40050 30 39 56
111 50053 30
111 45 30
112 131 49
112 132 45
112 133 43
112 134 50
112 135 48
112 136 47
112 137 44
112 138 30
112 139 29
112 140 46
113 109 46 11 109
114 84 48
115 116 49
116 115 47
116 593 30
117 118 49
117 233660 41 42 69 47
117 332661 41
117 303 41
117 332021 39
117 596 39
118 72 30
118 117 29
119 69 45 11
119 653 43 7
120 69 45
120 74 43
121 74 43 11
121 653 45 7
122 123 47
122 233660 41 42 69 49
122 303 41
122 596 39
122 124 77
122 126 28
122 129 40
123 122 44
123 124 43 77
123 126 28
123 129 40
124 123 44
124 125 47 36
124 128 48 37 30
124 126 28
124 129 40
125 124 46 77
125 126 45 28
125 127 43 17
126 125 46 23 11
126 124 77
126 610 30 39
127 125 44 11 17
127 124 77
127 126 28
128 124 45 29 77
128 129 46 30 40
128 126 28
129 128 44 29
129 124 77
129 130 43 19 40 3
129 126 28
130 129 44 11
130 124 77
130 126 28
131 107 44
131 132 48
131 133 50
131 134 49
131 135 47
131 136 29
131 137 30
131 138 45
131 139 46
131 112 43
132 107 50
132 131 29
132 133 45
132 134 46
132 135 44
132 136 49
132 137 47
132 138 43
132 139 30
132 112 48
133 107 29
133 131 30
133 132 44
133 134 47
133 135 49
133 136 43
133 137 45
133 138 50
133 139 48
133 112 46
134 107 47
134 131 45
134 132 50
134 133 48
134 135 43
134 136 30
134 137 46
134 138 29
134 139 44
134 112 49
135 107 45
135 131 48
135 132 30
135 133 46
135 134 43
135 136 44
135 137 49
135 138 47
135 139 50
135 112 29
136 107 43
136 131 44
136 132 29
136 133 49
136 134 30
136 135 46
136 137 50
136 138 48
136 139 47
136 112 45
137 107 48
137 131 47
137 132 46
137 133 30
137 134 29
137 135 50
137 136 45
137 138 49
137 139 43
137 112 44
138 107 30
138 131 43
138 132 47
138 133 29
138 134 44
138 135 45
138 136 46
138 137 48
138 139 49
138 112 50
139 107 49
139 131 50
139 132 43
139 133 44
139 134 45
139 135 30
139 136 48
139 137 29
139 138 46
139 112 47
140 112 45 11
-1
4
2 ROAD
2 HILL
3 ENTER
4 UPSTR
5 DOWNS
6 FORES
7 FORWA
7 CONTI
7 ONWAR
8 BACK
8 RETUR
8 RETRE
9 VALLE
10 STAIR
11 OUT
11 OUTSI
11 EXIT
11 LEAVE
12 BUILD
12 HOUSE
13 GULLY
14 STREA
15 ROCK
16 BED
17 CRAWL
18 COBBL
19 INWAR
19 INSID
19 IN
20 SURFA
21 NULL
21 NOWHE
22 DARK
23 PASSA
23 TUNNE
24 LOW
25 CANYO
26 AWKWA
27 GIANT
28 VIEW
29 UPWAR
29 UP
29 U
29 ABOVE
29 ASCEN
30 D
30 DOWNW
30 DOWN
30 DESCE
31 PIT
32 OUTDO
33 CRACK
34 STEPS
35 DOME
36 LEFT
37 RIGHT
38 HALL
39 JUMP
40 BARRE
41 OVER
42 ACROS
43 EAST
43 E
44 WEST
44 W
45 NORTH
45 N
46 SOUTH
46 S
47 NE
48 SE
49 SW
50 NW
51 DEBRI
52 HOLE
53 WALL
54 BROKE
55 Y2
56 CLIMB
57 LOOK
57 EXAMI
57 TOUCH
57 DESCR
58 FLOOR
59 ROOM
60 SLIT
61 SLAB
61 SLABR
62 XYZZY
63 DEPRE
64 ENTRA
65 PLUGH
66 SECRE
67 CAVE
69 CROSS
70 BEDQU
71 PLOVE
72 ORIEN
73 CAVER
74 SHELL
75 RESER
76 MAIN
76 OFFIC
77 FORK
1001 KEYS
1001 KEY
1002 LAMP
1002 HEADL
1002 LANTE
1003 GRATE
1004 CAGE
1005 ROD
1006 ROD (MUST BE NEXT OBJECT AFTER "REAL" ROD)
1007 STEPS
1008 BIRD
1009 DOOR
1010 PILLO
1010 VELVE
1011 SNAKE
1012 FISSU
1013 TABLE
1014 CLAM
1015 OYSTE
1016 MAGAZ
1016 ISSUE
1016 SPELU
1016 "SPEL
1017 DWARF
1017 DWARV
1018 KNIFE
1018 KNIVE
1019 FOOD
1019 RATIO
1020 BOTTL
1020 JAR
1021 WATER
1021 H2O
1022 OIL
1023 MIRRO
1024 PLANT
1024 BEANS
1025 PLANT (MUST BE NEXT OBJECT AFTER "REAL" PLANT)
1026 STALA
1027 SHADO
1027 FIGUR
1028 AXE
1029 DRAWI
1030 PIRAT
1031 DRAGO
1032 CHASM
1033 TROLL
1034 TROLL (MUST BE NEXT OBJECT AFTER "REAL" TROLL)
1035 BEAR
1036 MESSA
1037 VOLCA
1037 GEYSE (SAME AS VOLCANO)
1038 MACHI
1038 VENDI
1039 BATTE
1040 CARPE
1040 MOSS
1050 GOLD
1050 NUGGE
1051 DIAMO
1052 SILVE
1052 BARS
1053 JEWEL
1054 COINS
1055 CHEST
1055 BOX
1055 TREAS
1056 EGGS
1056 EGG
1056 NEST
1057 TRIDE
1058 VASE
1058 MING
1058 SHARD
1058 POTTE
1059 EMERA
1060 PLATI
1060 PYRAM
1061 PEARL
1062 RUG
1062 PERSI
1063 SPICE
1064 CHAIN
2001 CARRY
2001 TAKE
2001 KEEP
2001 CATCH
2001 STEAL
2001 CAPTU
2001 GET
2001 TOTE
2002 DROP
2002 RELEA
2002 FREE
2002 DISCA
2002 DUMP
2003 SAY
2003 CHANT
2003 SING
2003 UTTER
2003 MUMBL
2004 UNLOC
2004 OPEN
2005 NOTHI
2006 LOCK
2006 CLOSE
2007 LIGHT
2007 ON
2008 EXTIN
2008 OFF
2009 WAVE
2009 SHAKE
2009 SWING
2010 CALM
2010 PLACA
2010 TAME
2011 WALK
2011 RUN
2011 TRAVE
2011 GO
2011 PROCE
2011 CONTI
2011 EXPLO
2011 GOTO
2011 FOLLO
2011 TURN
2012 ATTAC
2012 KILL
2012 FIGHT
2012 HIT
2012 STRIK
2013 POUR
2014 EAT
2014 DEVOU
2015 DRINK
2016 RUB
2017 THROW
2017 TOSS
2018 QUIT
2019 FIND
2019 WHERE
2020 INVEN
2021 FEED
2022 FILL
2023 BLAST
2023 DETON
2023 IGNIT
2023 BLOWU
2024 SCORE
2025 FEE
2025 FIE
2025 FOE
2025 FOO
2025 FUM
2026 BRIEF
2027 READ
2027 PERUS
2028 BREAK
2028 SHATT
2028 SMASH
2029 WAKE
2029 DISTU
2030 SUSPE
2030 PAUSE
2030 SAVE
2031 HOURS
3001 FEE
3002 FIE
3003 FOE
3004 FOO
3005 FUM
3050 SESAM
3050 OPENS
3050 ABRA
3050 ABRAC
3050 SHAZA
3050 HOCUS
3050 POCUS
3051 HELP
3051 ?
3064 TREE
3064 TREES
3066 DIG
3066 EXCAV
3068 LOST
3069 MIST
3079 FUCK
3139 STOP
3142 INFO
3142 INFOR
3147 SWIM
-1
5
1 SET OF KEYS
000 THERE ARE SOME KEYS ON THE GROUND HERE.
2 BRASS LANTERN
000 THERE IS A SHINY BRASS LAMP NEARBY.
100 THERE IS A LAMP SHINING NEARBY.
3 *GRATE
000 THE GRATE IS LOCKED.
100 THE GRATE IS OPEN.
4 WICKER CAGE
000 THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
5 BLACK ROD
000 A THREE FOOT BLACK ROD WITH A RUSTY STAR ON AN END LIES NEARBY.
6 BLACK ROD
000 A THREE FOOT BLACK ROD WITH A RUSTY MARK ON AN END LIES NEARBY.
7 *STEPS
000 ROUGH STONE STEPS LEAD DOWN THE PIT.
100 ROUGH STONE STEPS LEAD UP THE DOME.
8 LITTLE BIRD IN CAGE
000 A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
100 THERE IS A LITTLE BIRD IN THE CAGE.
9 *RUSTY DOOR
000 THE WAY NORTH IS BARRED BY A MASSIVE, RUSTY, IRON DOOR.
100 THE WAY NORTH LEADS THROUGH A MASSIVE, RUSTY, IRON DOOR.
10 VELVET PILLOW
000 A SMALL VELVET PILLOW LIES ON THE FLOOR.
11 *SNAKE
000 A HUGE GREEN FIERCE SNAKE BARS THE WAY!
100 >$< (CHASED AWAY)
12 *FISSURE
000 >$<
100 A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
200 THE CRYSTAL BRIDGE HAS VANISHED!
13 *STONE TABLET
000 A MASSIVE STONE TABLET IMBEDDED IN THE WALL READS:
000 "CONGRATULATIONS ON BRINGING LIGHT INTO THE DARK-ROOM!"
14 GIANT CLAM >GRUNT!<
000 THERE IS AN ENORMOUS CLAM HERE WITH ITS SHELL TIGHTLY CLOSED.
15 GIANT OYSTER >GROAN!<
000 THERE IS AN ENORMOUS OYSTER HERE WITH ITS SHELL TIGHTLY CLOSED.
100 INTERESTING. THERE SEEMS TO BE SOMETHING WRITTEN ON THE UNDERSIDE OF
100 THE OYSTER.
16 "SPELUNKER TODAY"
000 THERE ARE A FEW RECENT ISSUES OF "SPELUNKER TODAY" MAGAZINE HERE.
19 TASTY FOOD
000 THERE IS FOOD HERE.
20 SMALL BOTTLE
000 THERE IS A BOTTLE OF WATER HERE.
100 THERE IS AN EMPTY BOTTLE HERE.
200 THERE IS A BOTTLE OF OIL HERE.
21 WATER IN THE BOTTLE
22 OIL IN THE BOTTLE
23 *MIRROR
000 >$<
24 *PLANT
000 THERE IS A TINY LITTLE PLANT IN THE PIT, MURMURING "WATER, WATER, ..."
100 THE PLANT SPURTS INTO FURIOUS GROWTH FOR A FEW SECONDS.
200 THERE IS A 12-FOOT-TALL BEANSTALK STRETCHING UP OUT OF THE PIT,
200 BELLOWING "WATER!! WATER!!"
300 THE PLANT GROWS EXPLOSIVELY, ALMOST FILLING THE BOTTOM OF THE PIT.
400 THERE IS A GIGANTIC BEANSTALK STRETCHING ALL THE WAY UP TO THE HOLE.
500 YOU'VE OVER-WATERED THE PLANT! IT'S SHRIVELING UP! IT'S, IT'S...
25 *PHONY PLANT (SEEN IN TWOPIT ROOM ONLY WHEN TALL ENOUGH)
000 >$<
100 THE TOP OF A 12-FOOT-TALL BEANSTALK IS POKING OUT OF THE WEST PIT.
200 THERE IS A HUGE BEANSTALK GROWING OUT OF THE WEST PIT UP TO THE HOLE.
26 *STALACTITE
000 >$<
27 *SHADOWY FIGURE
000 THE SHADOWY FIGURE SEEMS TO BE TRYING TO ATTRACT YOUR ATTENTION.
28 DWARF'S AXE
000 THERE IS A LITTLE AXE HERE.
100 THERE IS A LITTLE AXE LYING BESIDE THE BEAR.
29 *CAVE DRAWINGS
000 >$<
30 *PIRATE
000 >$<
31 *DRAGON
000 A HUGE GREEN FIERCE DRAGON BARS THE WAY!
100 CONGRATULATIONS! YOU HAVE JUST VANQUISHED A DRAGON WITH YOUR BARE
100 HANDS! (UNBELIEVABLE, ISN'T IT?)
200 THE BODY OF A HUGE GREEN DEAD DRAGON IS LYING OFF TO ONE SIDE.
32 *CHASM
000 A RICKETY WOODEN BRIDGE EXTENDS ACROSS THE CHASM, VANISHING INTO THE
000 MIST. A SIGN POSTED ON THE BRIDGE READS, "STOP! PAY TROLL!"
100 THE WRECKAGE OF A BRIDGE (AND A DEAD BEAR) CAN BE SEEN AT THE BOTTOM
100 OF THE CHASM.
33 *TROLL
000 A BURLY TROLL STANDS BY THE BRIDGE AND INSISTS YOU THROW HIM A
000 TREASURE BEFORE YOU MAY CROSS.
100 THE TROLL STEPS OUT FROM BENEATH THE BRIDGE AND BLOCKS YOUR WAY.
200 >$< (CHASED AWAY)
34 *PHONY TROLL
000 THE TROLL IS NOWHERE TO BE SEEN.
35 >$< (BEAR USES RTEXT 141)
000 THERE IS A FEROCIOUS CAVE BEAR EYING YOU FROM THE FAR END OF THE ROOM!
100 THERE IS A GENTLE CAVE BEAR SITTING PLACIDLY IN ONE CORNER.
200 THERE IS A CONTENTED-LOOKING BEAR WANDERING ABOUT NEARBY.
300 >$< (DEAD)
36 *MESSAGE IN SECOND MAZE
000 THERE IS A MESSAGE SCRAWLED IN THE DUST IN A FLOWERY SCRIPT, READING:
000 "THIS IS NOT THE MAZE WHERE THE PIRATE LEAVES HIS TREASURE CHEST."
37 *VOLCANO AND/OR GEYSER
000 >$<
38 *VENDING MACHINE
000 THERE IS A MASSIVE VENDING MACHINE HERE. THE INSTRUCTIONS ON IT READ:
000 "DROP COINS HERE TO RECEIVE FRESH BATTERIES."
39 BATTERIES
000 THERE ARE FRESH BATTERIES HERE.
100 SOME WORN-OUT BATTERIES HAVE BEEN DISCARDED NEARBY.
40 *CARPET AND/OR MOSS
000 >$<
50 LARGE GOLD NUGGET
000 THERE IS A LARGE SPARKLING NUGGET OF GOLD HERE!
51 SEVERAL DIAMONDS
000 THERE ARE DIAMONDS HERE!
52 BARS OF SILVER
000 THERE ARE BARS OF SILVER HERE!
53 PRECIOUS JEWELRY
000 THERE IS PRECIOUS JEWELRY HERE!
54 RARE COINS
000 THERE ARE MANY COINS HERE!
55 TREASURE CHEST
000 THE PIRATE'S TREASURE CHEST IS HERE!
56 GOLDEN EGGS
000 THERE IS A LARGE NEST HERE, FULL OF GOLDEN EGGS!
100 THE NEST OF GOLDEN EGGS HAS VANISHED!
200 DONE!
57 JEWELED TRIDENT
000 THERE IS A JEWEL-ENCRUSTED TRIDENT HERE!
58 MING VASE
000 THERE IS A DELICATE, PRECIOUS, MING VASE HERE!
100 THE VASE IS NOW RESTING, DELICATELY, ON A VELVET PILLOW.
200 THE FLOOR IS LITTERED WITH WORTHLESS SHARDS OF POTTERY.
300 THE MING VASE DROPS WITH A DELICATE CRASH.
59 EGG-SIZED EMERALD
000 THERE IS AN EMERALD HERE THE SIZE OF A PLOVER'S EGG!
60 PLATINUM PYRAMID
000 THERE IS A PLATINUM PYRAMID HERE, 8 INCHES ON A SIDE!
61 GLISTENING PEARL
000 OFF TO ONE SIDE LIES A GLISTENING PEARL!
62 PERSIAN RUG
000 THERE IS A PERSIAN RUG SPREAD OUT ON THE FLOOR!
100 THE DRAGON IS SPRAWLED OUT ON A PERSIAN RUG!!
63 RARE SPICES
000 THERE ARE RARE SPICES HERE!
64 GOLDEN CHAIN
000 THERE IS A GOLDEN CHAIN LYING IN A HEAP ON THE FLOOR!
100 THE BEAR IS LOCKED TO THE WALL WITH A GOLDEN CHAIN!
200 THERE IS A GOLDEN CHAIN LOCKED TO THE WALL!
-1
6
1 SOMEWHERE NEARBY IS COLOSSAL CAVE, WHERE OTHERS HAVE FOUND FORTUNES IN
1 TREASURE AND GOLD, THOUGH IT IS RUMORED THAT SOME WHO ENTER ARE NEVER
1 SEEN AGAIN. MAGIC IS SAID TO WORK IN THE CAVE. I WILL BE YOUR EYES
1 AND HANDS. DIRECT ME WITH COMMANDS OF 1 OR 2 WORDS. I SHOULD WARN
1 YOU THAT I LOOK AT ONLY THE FIRST FIVE LETTERS OF EACH WORD, SO YOU'LL
1 HAVE TO ENTER "NORTHEAST" AS "NE" TO DISTINGUISH IT FROM "NORTH".
1 (SHOULD YOU GET STUCK, TYPE "HELP" FOR SOME GENERAL HINTS. FOR INFOR-
1 MATION ON HOW TO END YOUR ADVENTURE, ETC., TYPE "INFO".)
1 - - -
1 THIS PROGRAM WAS ORIGINALLY DEVELOPED BY WILLIE CROWTHER. MOST OF THE
1 FEATURES OF THE CURRENT PROGRAM WERE ADDED BY DON WOODS (DON @ SU-AI).
1 CONTACT DON IF YOU HAVE ANY QUESTIONS, COMMENTS, ETC.
2 A LITTLE DWARF WITH A BIG KNIFE BLOCKS YOUR WAY.
3 A LITTLE DWARF JUST WALKED AROUND A CORNER, SAW YOU, THREW A LITTLE
3 AXE AT YOU WHICH MISSED, CURSED, AND RAN AWAY.
4 THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
5 ONE SHARP NASTY KNIFE IS THROWN AT YOU!
6 NONE OF THEM HIT YOU!
7 ONE OF THEM GETS YOU!
8 A HOLLOW VOICE SAYS "PLUGH".
9 THERE IS NO WAY TO GO THAT DIRECTION.
10 I AM UNSURE HOW YOU ARE FACING. USE COMPASS POINTS OR NEARBY OBJECTS.
11 I DON'T KNOW IN FROM OUT HERE. USE COMPASS POINTS OR NAME SOMETHING
11 IN THE GENERAL DIRECTION YOU WANT TO GO.
12 I DON'T KNOW HOW TO APPLY THAT WORD HERE.
13 I DON'T UNDERSTAND THAT!
14 I'M GAME. WOULD YOU CARE TO EXPLAIN HOW?
15 SORRY, BUT I AM NOT ALLOWED TO GIVE MORE DETAIL. I WILL REPEAT THE
15 LONG DESCRIPTION OF YOUR LOCATION.
16 IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
17 IF YOU PREFER, SIMPLY TYPE W RATHER THAN WEST.
18 ARE YOU TRYING TO CATCH THE BIRD?
19 THE BIRD IS FRIGHTENED RIGHT NOW AND YOU CANNOT CATCH IT NO MATTER
19 WHAT YOU TRY. PERHAPS YOU MIGHT TRY LATER.
20 ARE YOU TRYING TO SOMEHOW DEAL WITH THE SNAKE?
21 YOU CAN'T KILL THE SNAKE, OR DRIVE IT AWAY, OR AVOID IT, OR ANYTHING
21 LIKE THAT. THERE IS A WAY TO GET BY, BUT YOU DON'T HAVE THE NECESSARY
21 RESOURCES RIGHT NOW.
22 DO YOU REALLY WANT TO QUIT NOW?
23 YOU FELL INTO A PIT AND BROKE EVERY BONE IN YOUR BODY!
24 YOU ARE ALREADY CARRYING IT!
25 YOU CAN'T BE SERIOUS!
26 THE BIRD WAS UNAFRAID WHEN YOU ENTERED, BUT AS YOU APPROACH IT BECOMES
26 DISTURBED AND YOU CANNOT CATCH IT.
27 YOU CAN CATCH THE BIRD, BUT YOU CANNOT CARRY IT.
28 THERE IS NOTHING HERE WITH A LOCK!
29 YOU AREN'T CARRYING IT!
30 THE LITTLE BIRD ATTACKS THE GREEN SNAKE, AND IN AN ASTOUNDING FLURRY
30 DRIVES THE SNAKE AWAY.
31 YOU HAVE NO KEYS!
32 IT HAS NO LOCK.
33 I DON'T KNOW HOW TO LOCK OR UNLOCK SUCH A THING.
34 IT WAS ALREADY LOCKED.
35 THE GRATE IS NOW LOCKED.
36 THE GRATE IS NOW UNLOCKED.
37 IT WAS ALREADY UNLOCKED.
38 YOU HAVE NO SOURCE OF LIGHT.
39 YOUR LAMP IS NOW ON.
40 YOUR LAMP IS NOW OFF.
41 THERE IS NO WAY TO GET PAST THE BEAR TO UNLOCK THE CHAIN, WHICH IS
41 PROBABLY JUST AS WELL.
42 NOTHING HAPPENS.
43 WHERE?
44 THERE IS NOTHING HERE TO ATTACK.
45 THE LITTLE BIRD IS NOW DEAD. ITS BODY DISAPPEARS.
46 ATTACKING THE SNAKE BOTH DOESN'T WORK AND IS VERY DANGEROUS.
47 YOU KILLED A LITTLE DWARF.
48 YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
49 WITH WHAT? YOUR BARE HANDS?
50 GOOD TRY, BUT THAT IS AN OLD WORN-OUT MAGIC WORD.
51 I KNOW OF PLACES, ACTIONS, AND THINGS. MOST OF MY VOCABULARY
51 DESCRIBES PLACES AND IS USED TO MOVE YOU THERE. TO MOVE, TRY WORDS
51 LIKE FOREST, BUILDING, DOWNSTREAM, ENTER, EAST, WEST, NORTH, SOUTH,
51 UP, OR DOWN. I KNOW ABOUT A FEW SPECIAL OBJECTS, LIKE A BLACK ROD
51 HIDDEN IN THE CAVE. THESE OBJECTS CAN BE MANIPULATED USING SOME OF
51 THE ACTION WORDS THAT I KNOW. USUALLY YOU WILL NEED TO GIVE BOTH THE
51 OBJECT AND ACTION WORDS (IN EITHER ORDER), BUT SOMETIMES I CAN INFER
51 THE OBJECT FROM THE VERB ALONE. SOME OBJECTS ALSO IMPLY VERBS; IN
51 PARTICULAR, "INVENTORY" IMPLIES "TAKE INVENTORY", WHICH CAUSES ME TO
51 GIVE YOU A LIST OF WHAT YOU'RE CARRYING. THE OBJECTS HAVE SIDE
51 EFFECTS; FOR INSTANCE, THE ROD SCARES THE BIRD. USUALLY PEOPLE HAVING
51 TROUBLE MOVING JUST NEED TO TRY A FEW MORE WORDS. USUALLY PEOPLE
51 TRYING UNSUCCESSFULLY TO MANIPULATE AN OBJECT ARE ATTEMPTING SOMETHING
51 BEYOND THEIR (OR MY!) CAPABILITIES AND SHOULD TRY A COMPLETELY
51 DIFFERENT TACK. TO SPEED THE GAME YOU CAN SOMETIMES MOVE LONG
51 DISTANCES WITH A SINGLE WORD. FOR EXAMPLE, "BUILDING" USUALLY GETS
51 YOU TO THE BUILDING FROM ANYWHERE ABOVE GROUND EXCEPT WHEN LOST IN THE
51 FOREST. ALSO, NOTE THAT CAVE PASSAGES TURN A LOT, AND THAT LEAVING A
51 ROOM TO THE NORTH DOES NOT GUARANTEE ENTERING THE NEXT FROM THE SOUTH.
51 GOOD LUCK!
52 IT MISSES!
53 IT GETS YOU!
54 OK
55 YOU CAN'T UNLOCK THE KEYS.
56 YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
56 MAIN PASSAGE.
57 I DON'T KNOW WHERE THE CAVE IS, BUT HEREABOUTS NO STREAM CAN RUN ON
57 THE SURFACE FOR LONG. I WOULD TRY THE STREAM.
58 I NEED MORE DETAILED INSTRUCTIONS TO DO THAT.
59 I CAN ONLY TELL YOU WHAT YOU SEE AS YOU MOVE ABOUT AND MANIPULATE
59 THINGS. I CANNOT TELL YOU WHERE REMOTE THINGS ARE.
60 I DON'T KNOW THAT WORD.
61 WHAT?
62 ARE YOU TRYING TO GET INTO THE CAVE?
63 THE GRATE IS VERY SOLID AND HAS A HARDENED STEEL LOCK. YOU CANNOT
63 ENTER WITHOUT A KEY, AND THERE ARE NO KEYS NEARBY. I WOULD RECOMMEND
63 LOOKING ELSEWHERE FOR THE KEYS.
64 THE TREES OF THE FOREST ARE LARGE HARDWOOD OAK AND MAPLE, WITH AN
64 OCCASIONAL GROVE OF PINE OR SPRUCE. THERE IS QUITE A BIT OF UNDER-
64 GROWTH, LARGELY BIRCH AND ASH SAPLINGS PLUS NONDESCRIPT BUSHES OF
64 VARIOUS SORTS. THIS TIME OF YEAR VISIBILITY IS QUITE RESTRICTED BY
64 ALL THE LEAVES, BUT TRAVEL IS QUITE EASY IF YOU DETOUR AROUND THE
64 SPRUCE AND BERRY BUSHES.
65 WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
66 DDIGGING WITHOUT A SHOVEL IS QUITE IMPRACTICAL. EVEN WITH A SHOVEL
66 PROGRESS IS UNLIKELY.
67 BLASTING REQUIRES DYNAMITE.
68 I'M AS CONFUSED AS YOU ARE.
69 MIST IS A WHITE VAPOR, USUALLY WATER, SEEN FROM TIME TO TIME IN
69 CAVERNS. IT CAN BE FOUND ANYWHERE BUT IS FREQUENTLY A SIGN OF A DEEP
69 PIT LEADING DOWN TO WATER.
70 YOUR FEET ARE NOW WET.
71 I THINK I JUST LOST MY APPETITE.
72 THANK YOU, IT WAS DELICIOUS!
73 YOU HAVE TAKEN A DRINK FROM THE STREAM. THE WATER TASTES STRONGLY OF
73 MINERALS, BUT IS NOT UNPLEASANT. IT IS EXTREMELY COLD.
74 THE BOTTLE OF WATER IS NOW EMPTY.
75 RUBBING THE ELECTRIC LAMP IS NOT PARTICULARLY REWARDING. ANYWAY,
75 NOTHING EXCITING HAPPENS.
76 PECULIAR. NOTHING UNEXPECTED HAPPENS.
77 YOUR BOTTLE IS EMPTY AND THE GROUND IS WET.
78 YOU CAN'T POUR THAT.
79 WATCH IT!
80 WHICH WAY?
81 OH DEAR, YOU SEEM TO HAVE GOTTEN YOURSELF KILLED. I MIGHT BE ABLE TO
81 HELP YOU OUT, BUT I'VE NEVER REALLY DONE THIS BEFORE. DO YOU WANT ME
81 TO TRY TO REINCARNATE YOU?
82 ALL RIGHT. BUT DON'T BLAME ME IF SOMETHING GOES WR......
82 --- POOF!! ---
82 YOU ARE ENGULFED IN A CLOUD OF ORANGE SMOKE. COUGHING AND GASPING,
82 YOU EMERGE FROM THE SMOKE AND FIND....
83 YOU CLUMSY OAF, YOU'VE DONE IT AGAIN! I DON'T KNOW HOW LONG I CAN
83 KEEP THIS UP. DO YOU WANT ME TO TRY REINCARNATING YOU AGAIN?
84 OKAY, NOW WHERE DID I PUT MY ORANGE SMOKE?.... >POOF!<
84 EVERYTHING DISAPPEARS IN A DENSE CLOUD OF ORANGE SMOKE.
85 NOW YOU'VE REALLY DONE IT! I'M OUT OF ORANGE SMOKE! YOU DON'T EXPECT
85 ME TO DO A DECENT REINCARNATION WITHOUT ANY ORANGE SMOKE, DO YOU?
86 OKAY, IF YOU'RE SO SMART, DO IT YOURSELF! I'M LEAVING!
90 >>> MESSAGES 81 THRU 90 ARE RESERVED FOR "OBITUARIES". <<<
91 SORRY, BUT I NO LONGER SEEM TO REMEMBER HOW IT WAS YOU GOT HERE.
92 YOU CAN'T CARRY ANYTHING MORE. YOU'LL HAVE TO DROP SOMETHING FIRST.
93 YOU CAN'T GO THROUGH A LOCKED STEEL GRATE!
94 I BELIEVE WHAT YOU WANT IS RIGHT HERE WITH YOU.
95 YOU DON'T FIT THROUGH A TWO-INCH SLIT!
96 I RESPECTFULLY SUGGEST YOU GO ACROSS THE BRIDGE INSTEAD OF JUMPING.
97 THERE IS NO WAY ACROSS THE FISSURE.
98 YOU'RE NOT CARRYING ANYTHING.
99 YOU ARE CURRENTLY HOLDING THE FOLLOWING:
100 IT'S NOT HUNGRY (IT'S MERELY PININ' FOR THE FJORDS). BESIDES, YOU
100 HAVE NO BIRD SEED.
101 THE SNAKE HAS NOW DEVOURED YOUR BIRD.
102 THERE'S NOTHING HERE IT WANTS TO EAT (EXCEPT PERHAPS YOU).
103 YOU FOOL, DWARVES EAT ONLY COAL! NOW YOU'VE MADE HIM *REALLY* MAD!!
104 YOU HAVE NOTHING IN WHICH TO CARRY IT.
105 YOUR BOTTLE IS ALREADY FULL.
106 THERE IS NOTHING HERE WITH WHICH TO FILL THE BOTTLE.
107 YOUR BOTTLE IS NOW FULL OF WATER.
108 YOUR BOTTLE IS NOW FULL OF OIL.
109 YOU CAN'T FILL THAT.
110 DON'T BE RIDICULOUS!
111 THE DOOR IS EXTREMELY RUSTY AND REFUSES TO OPEN.
112 THE PLANT INDIGNANTLY SHAKES THE OIL OFF ITS LEAVES AND ASKS, "WATER?"
113 THE HINGES ARE QUITE THOROUGHLY RUSTED NOW AND WON'T BUDGE.
114 THE OIL HAS FREED UP THE HINGES SO THAT THE DOOR WILL NOW MOVE,
114 ALTHOUGH IT REQUIRES SOME EFFORT.
115 THE PLANT HAS EXCEPTIONALLY DEEP ROOTS AND CANNOT BE PULLED FREE.
116 THE DWARVES' KNIVES VANISH AS THEY STRIKE THE WALLS OF THE CAVE.
117 SOMETHING YOU'RE CARRYING WON'T FIT THROUGH THE TUNNEL WITH YOU.
117 YOU'D BEST TAKE INVENTORY AND DROP SOMETHING.
118 YOU CAN'T FIT THIS FIVE-FOOT CLAM THROUGH THAT LITTLE PASSAGE!
119 YOU CAN'T FIT THIS FIVE-FOOT OYSTER THROUGH THAT LITTLE PASSAGE!
120 I ADVISE YOU TO PUT DOWN THE CLAM BEFORE OPENING IT. >STRAIN!<
121 I ADVISE YOU TO PUT DOWN THE OYSTER BEFORE OPENING IT. >WRENCH!<
122 YOU DON'T HAVE ANYTHING STRONG ENOUGH TO OPEN THE CLAM.
123 YOU DON'T HAVE ANYTHING STRONG ENOUGH TO OPEN THE OYSTER.
124 A GLISTENING PEARL FALLS OUT OF THE CLAM AND ROLLS AWAY. GOODNESS,
124 THIS MUST REALLY BE AN OYSTER. (I NEVER WAS VERY GOOD AT IDENTIFYING
124 BIVALVES.) WHATEVER IT IS, IT HAS NOW SNAPPED SHUT AGAIN.
125 THE OYSTER CREAKS OPEN, REVEALING NOTHING BUT OYSTER INSIDE. IT
125 PROMPTLY SNAPS SHUT AGAIN.
126 YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND FOUND YOUR WAY
126 BLOCKED BY A RECENT CAVE-IN. YOU ARE NOW BACK IN THE MAIN PASSAGE.
127 THERE ARE FAINT RUSTLING NOISES FROM THE DARKNESS BEHIND YOU.
128 OUT FROM THE SHADOWS BEHIND YOU POUNCES A BEARDED PIRATE! "HAR, HAR,"
128 HE CHORTLES, "I'LL JUST TAKE ALL THIS BOOTY AND HIDE IT AWAY WITH ME
128 CHEST DEEP IN THE MAZE!" HE SNATCHES YOUR TREASURE AND VANISHES INTO
128 THE GLOOM.
129 A SEPULCHRAL VOICE REVERBERATING THROUGH THE CAVE, SAYS, "CAVE CLOSING
129 SOON. ALL ADVENTURERS EXIT IMMEDIATELY THROUGH MAIN OFFICE."
130 A MYSTERIOUS RECORDED VOICE GROANS INTO LIFE AND ANNOUNCES:
130 "THIS EXIT IS CLOSED. PLEASE LEAVE VIA MAIN OFFICE."
131 IT LOOKS AS THOUGH YOU'RE DEAD. WELL, SEEING AS HOW IT'S SO CLOSE TO
131 CLOSING TIME ANYWAY, I THINK WE'LL JUST CALL IT A DAY.
132 THE SEPULCHRAL VOICE ENTONES, "THE CAVE IS NOW CLOSED." AS THE ECHOES
132 FADE, THERE IS A BLINDING FLASH OF LIGHT (AND A SMALL PUFF OF ORANGE
132 SMOKE). . . . AS YOUR EYES REFOCUS, YOU LOOK AROUND AND FIND...
133 THERE IS A LOUD EXPLOSION, AND A TWENTY-FOOT HOLE APPEARS IN THE FAR
133 WALL, BURYING THE DWARVES IN THE RUBBLE. YOU MARCH THROUGH THE HOLE
133 AND FIND YOURSELF IN THE MAIN OFFICE, WHERE A CHEERING BAND OF
133 FRIENDLY ELVES CARRY THE CONQUERING ADVENTURER OFF INTO THE SUNSET.
134 THERE IS A LOUD EXPLOSION, AND A TWENTY-FOOT HOLE APPEARS IN THE FAR
134 WALL, BURYING THE SNAKES IN THE RUBBLE. A RIVER OF MOLTEN LAVA POURS
134 IN THROUGH THE HOLE, DESTROYING EVERYTHING IN ITS PATH, INCLUDING YOU!
135 THERE IS A LOUD EXPLOSION, AND YOU ARE SUDDENLY SPLASHED ACROSS THE
135 WALLS OF THE ROOM.
136 THE RESULTING RUCKUS HAS AWAKENED THE DWARVES. THERE ARE NOW SEVERAL
136 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU! MOST OF THEM THROW
136 KNIVES AT YOU! ALL OF THEM GET YOU!
137 OH, LEAVE THE POOR UNHAPPY BIRD ALONE.
138 I DARESAY WHATEVER YOU WANT IS AROUND HERE SOMEWHERE.
139 I DON'T KNOW THE WORD "STOP". USE "QUIT" IF YOU WANT TO GIVE UP.
140 YOU CAN'T GET THERE FROM HERE.
141 YOU ARE BEING FOLLOWED BY A VERY LARGE, TAME BEAR.
142 IF YOU WANT TO END YOUR ADVENTURE EARLY, SAY "QUIT". TO SUSPEND YOUR
142 ADVENTURE SUCH THAT YOU CAN CONTINUE LATER, SAY "SUSPEND" (OR "PAUSE"
142 OR "SAVE"). TO SEE WHAT HOURS THE CAVE IS NORMALLY OPEN, SAY "HOURS".
142 TO SEE HOW WELL YOU'RE DOING, SAY "SCORE". TO GET FULL CREDIT FOR A
142 TREASURE, YOU MUST HAVE LEFT IT SAFELY IN THE BUILDING, THOUGH YOU GET
142 PARTIAL CREDIT JUST FOR LOCATING IT. YOU LOSE POINTS FOR GETTING
142 KILLED, OR FOR QUITTING, THOUGH THE FORMER COSTS YOU MORE. THERE ARE
142 ALSO POINTS BASED ON HOW MUCH (IF ANY) OF THE CAVE YOU'VE MANAGED TO
142 EXPLORE; IN PARTICULAR, THERE IS A LARGE BONUS JUST FOR GETTING IN (TO
142 DISTINGUISH THE BEGINNERS FROM THE REST OF THE PACK), AND THERE ARE
142 OTHER WAYS TO DETERMINE WHETHER YOU'VE BEEN THROUGH SOME OF THE MORE
142 HARROWING SECTIONS. IF YOU THINK YOU'VE FOUND ALL THE TREASURES, JUST
142 KEEP EXPLORING FOR A WHILE. IF NOTHING INTERESTING HAPPENS, YOU
142 HAVEN'T FOUND THEM ALL YET. IF SOMETHING INTERESTING *DOES* HAPPEN,
142 IT MEANS YOU'RE GETTING A BONUS AND HAVE AN OPPORTUNITY TO GARNER MANY
142 MORE POINTS IN THE MASTER'S SECTION. I MAY OCCASIONALLY OFFER HINTS
142 IF YOU SEEM TO BE HAVING TROUBLE. IF I DO, I'LL WARN YOU IN ADVANCE
142 HOW MUCH IT WILL AFFECT YOUR SCORE TO ACCEPT THE HINTS. FINALLY, TO
142 SAVE PAPER, YOU MAY SPECIFY "BRIEF", WHICH TELLS ME NEVER TO REPEAT
142 THE FULL DESCRIPTION OF A PLACE UNLESS YOU EXPLICITLY ASK ME TO.
143 DO YOU INDEED WISH TO QUIT NOW?
144 THERE IS NOTHING HERE WITH WHICH TO FILL THE VASE.
145 THE SUDDEN CHANGE IN TEMPERATURE HAS DELICATELY SHATTERED THE VASE.
146 IT IS BEYOND YOUR POWER TO DO THAT.
147 I DON'T KNOW HOW.
148 IT IS TOO FAR UP FOR YOU TO REACH.
149 YOU KILLED A LITTLE DWARF. THE BODY VANISHES IN A CLOUD OF GREASY
149 BLACK SMOKE.
150 THE SHELL IS VERY STRONG AND IS IMPERVIOUS TO ATTACK.
151 WHAT'S THE MATTER, CAN'T YOU READ? NOW YOU'D BEST START OVER.
152 THE AXE BOUNCES HARMLESSLY OFF THE DRAGON'S THICK SCALES.
153 THE DRAGON LOOKS RATHER NASTY. YOU'D BEST NOT TRY TO GET BY.
154 THE LITTLE BIRD ATTACKS THE GREEN DRAGON, AND IN AN ASTOUNDING FLURRY
154 GETS BURNT TO A CINDER. THE ASHES BLOW AWAY.
155 ON WHAT?
156 OKAY, FROM NOW ON I'LL ONLY DESCRIBE A PLACE IN FULL THE FIRST TIME
156 YOU COME TO IT. TO GET THE FULL DESCRIPTION, SAY "LOOK".
157 TROLLS ARE CLOSE RELATIVES WITH THE ROCKS AND HAVE SKIN AS TOUGH AS
157 THAT OF A RHINOCEROS. THE TROLL FENDS OFF YOUR BLOWS EFFORTLESSLY.
158 THE TROLL DEFTLY CATCHES THE AXE, EXAMINES IT CAREFULLY, AND TOSSES IT
158 BACK, DECLARING, "GOOD WORKMANSHIP, BUT IT'S NOT VALUABLE ENOUGH."
159 THE TROLL CATCHES YOUR TREASURE AND SCURRIES AWAY OUT OF SIGHT.
160 THE TROLL REFUSES TO LET YOU CROSS.
161 THERE IS NO LONGER ANY WAY ACROSS THE CHASM.
162 JUST AS YOU REACH THE OTHER SIDE, THE BRIDGE BUCKLES BENEATH THE
162 WEIGHT OF THE BEAR, WHICH WAS STILL FOLLOWING YOU AROUND. YOU
162 SCRABBLE DESPERATELY FOR SUPPORT, BUT AS THE BRIDGE COLLAPSES YOU
162 STUMBLE BACK AND FALL INTO THE CHASM.
163 THE BEAR LUMBERS TOWARD THE TROLL, WHO LETS OUT A STARTLED SHRIEK AND
163 SCURRIES AWAY. THE BEAR SOON GIVES UP THE PURSUIT AND WANDERS BACK.
164 THE AXE MISSES AND LANDS NEAR THE BEAR WHERE YOU CAN'T GET AT IT.
165 WITH WHAT? YOUR BARE HANDS? AGAINST *HIS* BEAR HANDS??
166 THE BEAR IS CONFUSED; HE ONLY WANTS TO BE YOUR FRIEND.
167 FOR CRYING OUT LOUD, THE POOR THING IS ALREADY DEAD!
168 THE BEAR EAGERLY WOLFS DOWN YOUR FOOD, AFTER WHICH HE SEEMS TO CALM
168 DOWN CONSIDERABLY AND EVEN BECOMES RATHER FRIENDLY.
169 THE BEAR IS STILL CHAINED TO THE WALL.
170 THE CHAIN IS STILL LOCKED.
171 THE CHAIN IS NOW UNLOCKED.
172 THE CHAIN IS NOW LOCKED.
173 THERE IS NOTHING HERE TO WHICH THE CHAIN CAN BE LOCKED.
174 THERE IS NOTHING HERE TO EAT.
175 DO YOU WANT THE HINT?
176 DO YOU NEED HELP GETTING OUT OF THE MAZE?
177 YOU CAN MAKE THE PASSAGES LOOK LESS ALIKE BY DROPPING THINGS.
178 ARE YOU TRYING TO EXPLORE BEYOND THE PLOVER ROOM?
179 THERE IS A WAY TO EXPLORE THAT REGION WITHOUT HAVING TO WORRY ABOUT
179 FALLING INTO A PIT. NONE OF THE OBJECTS AVAILABLE IS IMMEDIATELY
179 USEFUL IN DISCOVERING THE SECRET.
180 DO YOU NEED HELP GETTING OUT OF HERE?
181 DON'T GO WEST.
182 GLUTTONY IS NOT ONE OF THE TROLL'S VICES. AVARICE, HOWEVER, IS.
183 YOUR LAMP IS GETTING DIM. YOU'D BEST START WRAPPING THIS UP, UNLESS
183 YOU CAN FIND SOME FRESH BATTERIES. I SEEM TO RECALL THERE'S A VENDING
183 MACHINE IN THE MAZE. BRING SOME COINS WITH YOU.
184 YOUR LAMP HAS RUN OUT OF POWER.
185 THERE'S NOT MUCH POINT IN WANDERING AROUND OUT HERE, AND YOU CAN'T
185 EXPLORE THE CAVE WITHOUT A LAMP. SO LET'S JUST CALL IT A DAY.
186 THERE ARE FAINT RUSTLING NOISES FROM THE DARKNESS BEHIND YOU. AS YOU
186 TURN TOWARD THEM, THE BEAM OF YOUR LAMP FALLS ACROSS A BEARDED PIRATE.
186 HE IS CARRYING A LARGE CHEST. "SHIVER ME TIMBERS!" HE CRIES, "I'VE
186 BEEN SPOTTED! I'D BEST HIE MESELF OFF TO THE MAZE TO HIDE ME CHEST!"
186 WITH THAT, HE VANISHES INTO THE GLOOM.
187 YOUR LAMP IS GETTING DIM. YOU'D BEST GO BACK FOR THOSE BATTERIES.
188 YOUR LAMP IS GETTING DIM. I'M TAKING THE LIBERTY OF REPLACING THE
188 BATTERIES.
189 YOUR LAMP IS GETTING DIM, AND YOU'RE OUT OF SPARE BATTERIES. YOU'D
189 BEST START WRAPPING THIS UP.
190 I'M AFRAID THE MAGAZINE IS WRITTEN IN DWARVISH.
191 "THIS IS NOT THE MAZE WHERE THE PIRATE LEAVES HIS TREASURE CHEST."
192 HMMM, THIS LOOKS LIKE A CLUE, WHICH MEANS IT'LL COST YOU 10 POINTS TO
192 READ IT. SHOULD I GO AHEAD AND READ IT ANYWAY?
193 IT SAYS, "THERE IS SOMETHING STRANGE ABOUT THIS PLACE, SUCH THAT ONE
193 OF THE WORDS I'VE ALWAYS KNOWN NOW HAS A NEW EFFECT."
194 IT SAYS THE SAME THING IT DID BEFORE.
195 I'M AFRAID I DON'T UNDERSTAND.
196 "CONGRATULATIONS ON BRINGING LIGHT INTO THE DARK-ROOM!"
197 YOU STRIKE THE MIRROR A RESOUNDING BLOW, WHEREUPON IT SHATTERS INTO A
197 MYRIAD TINY FRAGMENTS.
198 YOU HAVE TAKEN THE VASE AND HURLED IT DELICATELY TO THE GROUND.
199 YOU PROD THE NEAREST DWARF, WHO WAKES UP GRUMPILY, TAKES ONE LOOK AT
199 YOU, CURSES, AND GRABS FOR HIS AXE.
200 IS THIS ACCEPTABLE?
201 THERE'S NO POINT IN SUSPENDING A DEMONSTRATION GAME.
-1
7
1 3
2 3
3 8 9
4 10
5 11
6 0
7 14 15
8 13
9 94 -1
10 96
11 19 -1
12 17 27
13 101 -1
14 103
15 0
16 106
17 0 -1
18 0
19 3
20 3
21 0
22 0
23 109 -1
24 25 -1
25 23 67
26 111 -1
27 35 110
28 0
29 97 -1
30 0 -1
31 119 121
32 117 122
33 117 122
34 0 0
35 130 -1
36 0 -1
37 126 -1
38 140 -1
39 0
40 96 -1
50 18
51 27
52 28
53 29
54 30
55 0
56 92
57 95
58 97
59 100
60 101
61 0
62 119 121
63 127
64 130 -1
-1
8
1 24
2 29
3 0
4 33
5 0
6 33
7 38
8 38
9 42
10 14
11 43
12 110
13 29
14 110
15 73
16 75
17 29
18 13
19 59
20 59
21 174
22 109
23 67
24 13
25 147
26 155
27 195
28 146
29 110
30 13
31 13
-1
9
0 1 2 3 4 5 6 7 8 9 10
0 100 115 116 126
2 1 3 4 7 38 95 113 24
1 24
3 46 47 48 54 56 58 82 85 86
3 122 123 124 125 126 127 128 129 130
4 8
5 13
6 19
7 42 43 44 45 46 47 48 49 50 51
7 52 53 54 55 56 80 81 82 86 87
8 99 100 101
9 108
-1
10
35 YOU ARE OBVIOUSLY A RANK AMATEUR. BETTER LUCK NEXT TIME.
100 YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
130 YOU HAVE ACHIEVED THE RATING: "EXPERIENCED ADVENTURER".
200 YOU MAY NOW CONSIDER YOURSELF A "SEASONED ADVENTURER".
250 YOU HAVE REACHED "JUNIOR MASTER" STATUS.
300 YOUR SCORE PUTS YOU IN MASTER ADVENTURER CLASS C.
330 YOUR SCORE PUTS YOU IN MASTER ADVENTURER CLASS B.
349 YOUR SCORE PUTS YOU IN MASTER ADVENTURER CLASS A.
9999 ALL OF ADVENTUREDOM GIVES TRIBUTE TO YOU, ADVENTURER GRANDMASTER!
-1
11
2 9999 10 0 0
3 9999 5 0 0
4 4 2 62 63
5 5 2 18 19
6 8 2 20 21
7 75 4 176 177
8 25 5 178 179
9 20 3 180 181
-1
12
1 A LARGE CLOUD OF GREEN SMOKE APPEARS IN FRONT OF YOU. IT CLEARS AWAY
1 TO REVEAL A TALL WIZARD, CLOTHED IN GREY. HE FIXES YOU WITH A STEELY
1 GLARE AND DECLARES, "THIS ADVENTURE HAS LASTED TOO LONG." WITH THAT
1 HE MAKES A SINGLE PASS OVER YOU WITH HIS HANDS, AND EVERYTHING AROUND
1 YOU FADES AWAY INTO A GREY NOTHINGNESS.
2 EVEN WIZARDS HAVE TO WAIT LONGER THAN THAT!
3 I'M TERRIBLY SORRY, BUT COLOSSAL CAVE IS CLOSED. OUR HOURS ARE:
4 ONLY WIZARDS ARE PERMITTED WITHIN THE CAVE RIGHT NOW.
5 WE DO ALLOW VISITORS TO MAKE SHORT EXPLORATIONS DURING OUR OFF HOURS.
5 WOULD YOU LIKE TO DO THAT?
6 COLOSSAL CAVE IS OPEN TO REGULAR ADVENTURERS AT THE FOLLOWING HOURS:
7 VERY WELL.
8 ONLY A WIZARD MAY CONTINUE AN ADVENTURE THIS SOON.
9 I SUGGEST YOU RESUME YOUR ADVENTURE AT A LATER TIME.
10 DO YOU WISH TO SEE THE HOURS?
11 DO YOU WISH TO CHANGE THE HOURS?
12 NEW MAGIC WORD (NULL TO LEAVE UNCHANGED):
13 NEW MAGIC NUMBER (NULL TO LEAVE UNCHANGED):
14 DO YOU WISH TO CHANGE THE MESSAGE OF THE DAY?
15 OKAY. YOU CAN SAVE THIS VERSION NOW.
16 ARE YOU A WIZARD?
17 PROVE IT! SAY THE MAGIC WORD!
18 THAT IS NOT WHAT I THOUGHT IT WAS. DO YOU KNOW WHAT I THOUGHT IT WAS?
19 OH DEAR, YOU REALLY *ARE* A WIZARD! SORRY TO HAVE BOTHERED YOU . . .
20 FOO, YOU ARE NOTHING BUT A CHARLATAN!
21 NEW HOURS SPECIFIED BY DEFINING "PRIME TIME". GIVE ONLY THE HOUR
21 (E.G. 14, NOT 14:00 OR 2PM). ENTER A NEGATIVE NUMBER AFTER LAST PAIR.
22 NEW HOURS FOR COLOSSAL CAVE:
23 LIMIT LINES TO 70 CHARS. END WITH NULL LINE.
24 LINE TOO LONG, RETYPE:
25 NOT ENOUGH ROOM FOR ANOTHER LINE. ENDING MESSAGE HERE.
26 DO YOU WISH TO (RE)SCHEDULE THE NEXT HOLIDAY?
27 TO BEGIN HOW MANY DAYS FROM TODAY?
28 TO LAST HOW MANY DAYS (ZERO IF NO HOLIDAY)?
29 TO BE CALLED WHAT (UP TO 20 CHARACTERS)?
30 TOO SMALL! ASSUMING MINIMUM VALUE (45 MINUTES).
31 BREAK OUT OF THIS AND SAVE YOUR CORE-IMAGE.
32 BE SURE TO SAVE YOUR CORE-IMAGE...
-1
0
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1597411765.0
adventure-1.7/adventure/data.py 0000640 0001750 0001750 00000034662 13715510665 016546 0 ustar 00brandon brandon # -*- coding: utf-8 -*-
"""Parse the original PDP ``advent.dat`` file.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
from operator import attrgetter
from .model import Hint, Message, Move, Object, Room, Word
# The Adventure data file knows only the first five characters of each
# word in the game, so we have to know the full verion of each word.
long_words = { w[:5]: w for w in """upstream downstream forest
forward continue onward return retreat valley staircase outside building stream
cobble inward inside surface nowhere passage tunnel canyon awkward
upward ascend downward descend outdoors barren across debris broken
examine describe slabroom depression entrance secret bedquilt plover
oriental cavern reservoir office headlamp lantern pillow velvet fissure tablet
oyster magazine spelunker dwarves knives rations bottle mirror beanstalk
stalactite shadow figure drawings pirate dragon message volcano geyser
machine vending batteries carpet nuggets diamonds silver jewelry treasure
trident shards pottery emerald platinum pyramid pearl persian spices capture
release discard mumble unlock nothing extinguish placate travel proceed
continue explore follow attack strike devour inventory detonate ignite
blowup peruse shatter disturb suspend sesame opensesame abracadabra
shazam excavate information""".split() }
class Data(object):
def __init__(self):
self.rooms = {}
self.vocabulary = {}
self.objects = {}
self.messages = {}
self.class_messages = []
self.hints = {}
self.magic_messages = {}
def referent(self, word):
if word.kind == 'noun':
return self.objects[word.n % 1000]
# Helper functions.
def make_object(dictionary, klass, n):
if n not in dictionary:
dictionary[n] = obj = klass()
obj.n = n
return dictionary[n]
def expand_tabs(segments):
it = iter(segments)
line = next(it)
for segment in it:
spaces = 8 - len(line) % 8
line += ' ' * spaces + segment
return line
def accumulate_message(dictionary, n, line):
dictionary[n] = dictionary.get(n, '') + line + '\n'
# Knowledge of what each section contains.
def section1(data, n, *etc):
"""Handle record from “Section 1: long form descriptions”.
Section 1: long form descriptions. Each line contains a location
number, a TAB, and a line of text. The set of (necessarily adjacent)
lines whose numbers are X form the long description of location X.
"""
room = make_object(data.rooms, Room, n)
if not etc[0].startswith('>$<'):
room.long_description += expand_tabs(etc) + '\n'
def section2(data, n, line):
"""Handle record from “Section 2: short form descriptions”.
Section 2: short form descriptions. Same format as long form. Not
all places have short descriptions.
"""
make_object(data.rooms, Room, n).short_description += line + '\n'
def section3(data, x, y, *verbs):
"""Handle record from “Section 3: travel table”.
Section 3: travel table. Each line contains a location number (X), a
second location number (Y), and a list of motion numbers (see
section 4).
Each motion represents a verb which will go to Y if currently at
X. Y, in turn, is interpreted as follows. Let M=Y/1000, N=Y MOD
1000.
If N<=300: it is the location to go to.
If 300500: message N-500 from section 6 is printed, and he
stays wherever he is.
Meanwhile, M specifies the conditions on the motion.
If M=0: it's unconditional.
If 0= 50)
data.objects[text] = obj
if text not in data.vocabulary: # since duplicate names exist
data.vocabulary[text] = word
def section5(data, n, *etc):
"""Handle record from “Section 5: object descriptions”.
Section 5: object descriptions. Each line contains a number (N), a
TAB, and a message. If N is from 1 to 100, the message is the
"inventory" message for object N. Otherwise, N should be 000, 100,
200, etc., and the message should be the description of the
preceding object when its PROP value is N/100. The N/100 is used
only to distinguish multiple messages from multi-line messages; the
PROP info actually requires all messages for an object to be present
and consecutive. Properties which produce no message should be
given the message ">$<".
"""
if 1 <= n <= 99:
data._object = make_object(data.objects, Object, n)
data._object.inventory_message = expand_tabs(etc)
else:
n //= 100
messages = data._object.messages
if etc[0].startswith('>$<'):
more = ''
else:
more = expand_tabs(etc) + '\n'
messages[n] = messages.get(n, '') + more
def section6(data, n, *etc):
"""Handle record from “Section 6: arbitrary messages”.
Section 6: arbitrary messages. Same format as sections 1, 2, and 5,
except the numbers bear no relation to anything (except for special
verbs in section 4).
"""
message = make_object(data.messages, Message, n)
message.text += expand_tabs(etc) + '\n'
def section7(data, n, room_n, fixed=None):
"""Handle record from “Section 7: object locations”.
Section 7: object locations. Each line contains an object number and
its initial location (zero (or omitted) if none). If the object is
immovable, the location is followed by a "-1". If it has two
locations (e.g. the grate) the first location is followed with the
second, and the object is assumed to be immovable.
"""
obj = make_object(data.objects, Object, n)
if room_n:
room = make_object(data.rooms, Room, room_n)
obj.drop(room)
if fixed is not None:
if fixed == -1:
obj.is_fixed = True
else:
room2 = make_object(data.rooms, Room, fixed)
obj.rooms.append(room2) # exists two places, like grate
obj.starting_rooms = list(obj.rooms) # remember where things started
def section8(data, word_n, message_n):
"""Handle record from “Section 8: action defaults”.
Section 8: action defaults. Each line contains an "action-verb"
number and the index (in section 6) of the default message for the
verb.
"""
if not message_n:
return
word = make_object(data.vocabulary, Word, word_n + 2000)
message = make_object(data.messages, Message, message_n)
for word2 in word.synonyms:
word2.default_message = message
def section9(data, bit, *nlist):
"""Handle record from “Section 9: liquid assets, etc.”.
Section 9: liquid assets, etc. Each line contains a number (N) and
up to 20 location numbers. Bit N (where 0 is the units bit) is set
in COND(LOC) for each LOC given. The COND bits currently assigned
are:
0: light
1: if bit 2 is on: on for oil, off for water
2: liquid asset, see bit 1
3: pirate doesn't go here unless following player
Other bits are used to indicate areas of interest to "hint"
routines:
4: trying to get into cave
5: trying to catch bird
6: trying to deal with snake
7: lost in maze
8: pondering dark room
9: at Witt's End
COND(LOC) is set to 2, overriding all other bits, if LOC has forced
motion.
"""
for n in nlist:
room = make_object(data.rooms, Room, n)
if bit == 0:
room.is_light = True
elif bit == 1:
room.liquid = make_object(data.objects, Object, 22) #oil
elif bit == 2:
room.liquid = make_object(data.objects, Object, 21) #water
elif bit == 3:
room.is_forbidden_to_pirate = True
else:
hint = make_object(data.hints, Hint, bit)
hint.rooms.append(room)
def section10(data, score, line, *etc):
"""Handle record from “Section 10: class messages”.
Section 10: class messages. Each line contains a number (N), a TAB,
and a message describing a classification of player. The scoring
section selects the appropriate message, where each message is
considered to apply to players whose scores are higher than the
previous N but not higher than this N. Note that these scores
probably change with every modification (and particularly expansion)
of the program.
"""
data.class_messages.append((score, line))
def section11(data, n, turns_needed, penalty, question_n, message_n):
"""Handle record from “Section 11: hints”.
Section 11: hints. Each line contains a hint number (corresponding
to a COND bit, see section 9), the number of turns he must be at the
right LOC(s) before triggering the hint, the points deducted for
taking the hint, the message number (section 6) of the question, and
the message number of the hint. These values are stashed in the
"HINTS" array.
HNTMAX is set to the max hint number (<= HNTSIZ). Numbers 1-3 are
unusable since COND bits are otherwise assigned, so 2 is used to
remember if he's read the clue in the repository, and 3 is used to
remember whether he asked for instructions (gets more turns, but
loses points).
"""
hint = make_object(data.hints, Hint, n)
hint.turns_needed = turns_needed
hint.penalty = penalty
hint.question = make_object(data.messages, Message, question_n)
hint.message = make_object(data.messages, Message, message_n)
def section12(data, n, line):
"""Handle record from “Section 12: magic messages”.
Section 12: magic messages. Identical to section 6 except put in a
separate section for easier reference. Magic messages are used by
the startup, maintenance mode, and related routines.
"""
accumulate_message(data.magic_messages, n, line)
# Process every section of the file in turn.
def parse(data, datafile):
"""Read the Adventure data file and return a ``Data`` object."""
data._last_travel = [0, [0]] # x and verbs used by section 3
while True:
section_number = int(datafile.readline())
if not section_number: # no further sections
break
store = globals().get('section%d' % section_number)
while True:
fields = [ (int(field) if field.lstrip('-').isdigit() else field)
for field in datafile.readline().strip().split('\t') ]
if fields[0] == -1: # end-of-section marker
break
store(data, *fields)
del data._last_travel # state used by section 3
del data._object # state used by section 5
data.object_list = sorted(set(data.objects.values()), key=attrgetter('n'))
#data.room_list = sorted(set(data.rooms.values()), key=attrgetter('n'))
for obj in data.object_list:
name = obj.names[0]
if hasattr(data, name):
name = name + '2' # create identifiers like ROD2, PLANT2
setattr(data, name, obj)
return data
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1597453554.0
adventure-1.7/adventure/game.py 0000664 0001750 0001750 00000167143 13715632362 016554 0 ustar 00brandon brandon """How we keep track of the state of the game.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
# Numeric comments scattered through this file refer to FORTRAN line
# numbers, for those comparing this file and `advent.for`; so "#2012"
# refers to FORTRAN line number 2012 (which you can find easily in the
# FORTRAN using Emacs with an interactive search for newline-2012-tab,
# that is typed C-s C-q C-j 2 0 1 2 C-i).
import os
import pickle
import random
import zlib
from operator import attrgetter
from .data import Data
from .model import Room, Message, Dwarf, Pirate
YESNO_ANSWERS = {'y': True, 'yes': True, 'n': False, 'no': False}
class Game(Data):
look_complaints = 3 # how many times to "SORRY, BUT I AM NOT ALLOWED..."
full_description_period = 5 # how often we use a room's full description
full_wests = 0 # how many times they have typed "west" instead of "w"
dwarf_stage = 0 # DFLAG how active the dwarves are
dwarves_killed = 0 # DKILL
knife_location = None # KNFLOC
foobar = -1 # FOOBAR turn number of most recent still-valid "fee"
gave_up = False
treasures_not_found = 0 # TALLY how many treasures have not yet been seen
impossible_treasures = 0 # TALLY2 how many treasures can never be retrieved
lamp_turns = 330
warned_about_dim_lamp = False
bonus = 0 # how they exited the final bonus round
is_dead = False # whether we are currently dead
deaths = 0 # how many times the player has died
max_deaths = 3 # how many times the player can die
turns = 0
def __init__(self, seed=None):
Data.__init__(self)
self.output = ''
self.yesno_callback = False
self.yesno_casual = False # whether to insist they answer
self.clock1 = 30 # counts down from finding last treasure
self.clock2 = 50 # counts down until cave closes
self.is_closing = False # is the cave closing?
self.panic = False # they tried to leave during closing?
self.is_closed = False # is the cave closed?
self.is_done = False # caller can check for "game over"
self.could_fall_in_pit = False # could the player fall into a pit?
self.random_generator = random.Random()
if seed is not None:
self.random_generator.seed(seed)
def random(self):
return self.random_generator.random()
def choice(self, seq):
return self.random_generator.choice(seq)
def write(self, more):
"""Append the Unicode representation of `s` to our output."""
if more:
self.output += str(more).upper()
self.output += '\n'
def write_message(self, n):
self.write(self.messages[n])
def yesno(self, s, yesno_callback, casual=False):
"""Ask a question and prepare to receive a yes-or-no answer."""
self.write(s)
self.yesno_callback = yesno_callback
self.yesno_casual = casual
# Properties of the cave.
@property
def is_dark(self):
lamp = self.objects['lamp']
if self.is_here(lamp) and lamp.prop:
return False
return self.loc.is_dark
@property
def inventory(self):
return [ obj for obj in self.object_list if obj.is_toting ]
@property
def treasures(self):
return [ obj for obj in self.object_list if obj.is_treasure ]
@property
def objects_here(self):
return self.objects_at(self.loc)
def objects_at(self, room):
return [obj for obj in self.object_list if obj.is_at(room)]
def is_here(self, obj):
if isinstance(obj, Dwarf):
return self.loc is obj.room
else:
return obj.is_toting or obj.is_at(self.loc)
@property
def is_finished(self):
return (self.is_dead or self.is_done) and not self.yesno_callback
# Game startup
def start(self):
"""Start the game."""
# For old-fashioned players, accept five-letter truncations like
# "inven" instead of insisting on full words like "inventory".
for key, value in list(self.vocabulary.items()):
if isinstance(key, str) and len(key) > 5:
self.vocabulary[key[:5]] = value
# Set things going.
self.chest_room = self.rooms[114]
self.bottle.contents = self.water
self.yesno(self.messages[65], self.start2) # want instructions?
def start2(self, yes):
"""Display instructions if the user wants them."""
if yes:
self.write_message(1)
self.hints[3].used = True
self.lamp_turns = 1000
self.oldloc2 = self.oldloc = self.loc = self.rooms[1]
self.dwarves = [ Dwarf(self.rooms[n]) for n in (19, 27, 33, 44, 64) ]
self.pirate = Pirate(self.chest_room)
treasures = self.treasures
self.treasures_not_found = len(treasures)
for treasure in treasures:
treasure.prop = -1
self.describe_location()
# Routines that handle the aftermath of "big" actions like movement.
# Although these are called at the end of each `do_command()` cycle,
# we place here at the top of `game.py` to mirror the order in the
# advent.for file.
def move_to(self, newloc=None): #2
loc = self.loc
if newloc is None:
newloc = loc
if self.is_closing and newloc.is_aboveground:
self.write_message(130)
newloc = loc # cancel move and put him back underground
if not self.panic:
self.clock2 = 15
self.panic = True
must_allow_move = ((newloc is loc) or (loc.is_forced)
or (loc.is_forbidden_to_pirate))
dwarf_blocking_the_way = any(
dwarf.old_room is newloc and dwarf.has_seen_adventurer
for dwarf in self.dwarves
)
if not must_allow_move and dwarf_blocking_the_way:
newloc = loc # cancel move they were going to make
self.write_message(2) # dwarf is blocking the way
self.loc = loc = newloc #74
# IF LOC.EQ.0 ?
is_dwarf_area = not (loc.is_forced or loc.is_forbidden_to_pirate)
if is_dwarf_area and self.dwarf_stage > 0:
self.move_dwarves()
else:
if is_dwarf_area and loc.is_after_hall_of_mists:
self.dwarf_stage = 1
self.describe_location()
def move_dwarves(self):
#6000
if self.dwarf_stage == 1:
# 5% chance per turn of meeting first dwarf
if self.loc.is_before_hall_of_mists or self.random() < .95:
self.describe_location()
return
self.dwarf_stage = 2
for i in range(2): # randomly remove 0, 1, or 2 dwarves
if self.random() < .5:
self.dwarves.remove(self.choice(self.dwarves))
for dwarf in self.dwarves:
if dwarf.room is self.loc: # move dwarf away from our loc
dwarf.start_at(self.rooms[18])
self.write_message(3) # dwarf throws axe and curses
self.axe.drop(self.loc)
self.describe_location()
return
#6010
dwarf_count = dwarf_attacks = knife_wounds = 0
for dwarf in self.dwarves + [ self.pirate ]:
locations = { move.action for move in dwarf.room.travel_table
if dwarf.can_move(move)
and move.action is not dwarf.old_room
and move.action is not dwarf.room }
# Without stabilizing the order with a sort, the room chosen
# would depend on how the Room addresses in memory happen to
# order the rooms in the set() - and make it impossible to
# test the game by setting the random number generator seed
# and then playing through the game.
locations = sorted(locations, key=attrgetter('n'))
if locations:
new_room = self.choice(locations)
else:
new_room = dwarf.old_room
dwarf.old_room, dwarf.room = dwarf.room, new_room
if self.loc in (dwarf.room, dwarf.old_room):
dwarf.has_seen_adventurer = True
elif self.loc.is_before_hall_of_mists:
dwarf.has_seen_adventurer = False
if not dwarf.has_seen_adventurer:
continue
dwarf.room = self.loc
if dwarf.is_dwarf:
dwarf_count += 1
# A dwarf cannot walk and attack at the same time.
if dwarf.room is dwarf.old_room:
dwarf_attacks += 1
self.knife_location = self.loc
if self.random() < .095 * (self.dwarf_stage - 2):
knife_wounds += 1
else: # the pirate
pirate = dwarf
if self.loc is self.chest_room or self.chest.prop >= 0:
continue # decide that the pirate is not really here
treasures = [ t for t in self.treasures if t.is_toting ]
if (self.platinum in treasures and self.loc.n in (100, 101)):
treasures.remove(self.platinum)
if not treasures:
h = any( t for t in self.treasures if self.is_here(t) )
one_treasure_left = (self.treasures_not_found ==
self.impossible_treasures + 1)
shiver_me_timbers = (
one_treasure_left and not h and not(self.chest.rooms)
and self.is_here(self.lamp) and self.lamp.prop == 1
)
if not shiver_me_timbers:
if (pirate.old_room != pirate.room
and self.random() < .2):
self.write_message(127)
continue # pragma: no cover
self.write_message(186)
self.chest.drop(self.chest_room)
self.message.drop(self.rooms[140])
else:
#6022 I'll just take all this booty
self.write_message(128)
if not self.message.rooms:
self.chest.drop(self.chest_room)
self.message.drop(self.rooms[140])
for treasure in treasures:
treasure.drop(self.chest_room)
#6024
pirate.old_room = pirate.room = self.chest_room
pirate.has_seen_adventurer = False # free to move
# Report what has happened.
if dwarf_count == 1:
self.write_message(4)
elif dwarf_count:
self.write('There are {} threatening little dwarves in the'
' room with you.\n'.format(dwarf_count))
if dwarf_attacks and self.dwarf_stage == 2:
self.dwarf_stage = 3
if dwarf_attacks == 1:
self.write_message(5)
k = 52
elif dwarf_attacks:
self.write('{} of them throw knives at you!\n'.format(dwarf_attacks))
k = 6
if not dwarf_attacks:
pass
elif not knife_wounds:
self.write_message(k)
else:
if knife_wounds == 1:
self.write_message(k + 1)
else:
self.write('{} of them get you!\n'.format(knife_wounds))
self.oldloc2 = self.loc
self.die()
return
self.describe_location()
def describe_location(self): #2000
loc = self.loc
if loc.n == 0:
self.die()
could_fall = self.is_dark and self.could_fall_in_pit
if could_fall and not loc.is_forced and self.random() < .35:
self.die_here()
return
if self.bear.is_toting:
self.write_message(141)
if self.is_dark and not loc.is_forced:
self.write_message(16)
else:
do_short = loc.times_described % self.full_description_period
loc.times_described += 1
if do_short and loc.short_description:
self.write(loc.short_description)
else:
self.write(loc.long_description)
if loc.is_forced:
self.do_motion(self.vocabulary[2]) # dummy motion verb
return
if loc.n == 33 and self.random() < .25 and not self.is_closing:
self.write_message(8)
# for obj in self.objects.values():
# if obj.rooms and [room.n for room in obj.rooms] != [115]:
# if (len(obj.messages) == 0) or (0 not in obj.messages):
# raise ValueError('%r %r' % (obj, obj.rooms))
# print(obj, obj.rooms)
if not self.is_dark:
for obj in self.objects_here:
if obj is self.steps and self.gold.is_toting:
continue
if obj.prop < 0: # finding a treasure the first time
if self.is_closed:
continue
obj.prop = 1 if obj in (self.rug, self.chain) else 0
self.treasures_not_found -= 1
if (self.treasures_not_found > 0 and
self.treasures_not_found == self.impossible_treasures):
self.lamp_turns = min(35, self.lamp_turns)
if obj is self.steps and self.loc is self.steps.rooms[1]:
prop = 1
else:
prop = obj.prop
self.write(obj.messages[prop])
self.finish_turn()
def say_okay_and_finish(self, *ignored): #2009
self.write_message(54)
self.finish_turn()
#2009 sets SPK="OK" then...
#2010 sets SPK to K
#2011 speaks SPK then...
#2012 blanks VERB and OBJ and calls:
def finish_turn(self, obj=None): #2600
# Advance random number generator so each input affects future.
self.random()
# Check whether we should offer a hint.
for hint in self.hints.values():
if hint.turns_needed == 9999 or hint.used:
continue
if self.loc in hint.rooms:
hint.turn_counter += 1
if hint.turn_counter >= hint.turns_needed:
if hint.n != 5: # hint 5 counter does not get reset
hint.turn_counter = 0
if self.should_offer_hint(hint, obj):
hint.turn_counter = 0
def callback(yes):
if yes:
self.write(hint.message)
hint.used = True
else:
self.write_message(54)
self.yesno(hint.question, callback)
return
else:
hint.turn_counter = 0
if self.is_closed:
if self.oyster.prop < 0 and self.oyster.is_toting:
self.write(self.oyster.messages[1])
for obj in self.inventory:
if obj.prop < 0:
obj.prop = - 1 - obj.prop
self.could_fall_in_pit = self.is_dark #2605
if self.knife_location and self.knife_location is not self.loc:
self.knife_location = None
# The central do_command() method, that should be called over and
# over again with words supplied by the user.
def do_command(self, words):
"""Parse and act upon the command in the list of strings `words`."""
self.output = ''
self._do_command(words)
return self.output
def _do_command(self, words):
if self.yesno_callback is not None:
answer = YESNO_ANSWERS.get(words[0], None)
if answer is None:
if self.yesno_casual:
self.yesno_callback = None
else:
self.write('Please answer the question.')
return
else:
callback = self.yesno_callback
self.yesno_callback = None
callback(answer)
return
if self.is_dead:
self.write('You have gotten yourself killed.')
return
#2608
self.turns += 1
if (self.treasures_not_found == 0
and self.loc.n >= 15 and self.loc.n != 33):
self.clock1 -= 1
if self.clock1 == 0:
self.start_closing_cave() # no "return", to do their command
if self.clock1 < 0:
self.clock2 -= 1
if self.clock2 == 0:
return self.close_cave() # "return", to cancel their command
if self.lamp.prop == 1:
self.lamp_turns -= 1
if self.lamp_turns <= 30 and self.is_here(self.batteries) \
and self.batteries.prop == 0 and self.is_here(self.lamp):
#12000
self.write_message(188)
self.batteries.prop = 1
if self.batteries.is_toting:
self.batteries.drop(self.loc)
self.lamp_turns += 2500
self.warned_about_dim_lamp = False
elif self.lamp_turns == 0:
#12400
self.lamp_turns = -1
self.lamp.prop = 0
if self.is_here(self.lamp):
self.write_message(184)
elif self.lamp_turns < 0 and self.loc.is_aboveground:
#12600
self.write_message(185)
self.gave_up = True
self.score_and_exit()
return
elif self.lamp_turns <= 30 and not self.warned_about_dim_lamp \
and self.is_here(self.lamp):
#12200
self.warned_about_dim_lamp = True
if self.batteries.prop == 1:
self.write_message(189)
elif not self.batteries.rooms:
self.write_message(183)
else:
self.write_message(187)
self.dispatch_command(words)
def dispatch_command(self, words): #19999
if not 1 <= len(words) <= 2:
return self.dont_understand()
if words[0] == 'save' and len(words) > 1:
# Handle suspend separately, since filename can be anything,
# and is not restricted to being a vocabulary word (and, in
# fact, it can be an open file).
return self.t_suspend(words[0], words[1])
words = [ self.vocabulary.get(word) for word in words ]
if None in words:
return self.dont_understand()
word1 = words[0]
word2 = words[1] if len(words) == 2 else None
if word1 == 'enter' and (word2 == 'stream' or word2 == 'water'):
if self.loc.liquid is self.water:
self.write_message(70)
else:
self.write_message(43)
return self.finish_turn()
if (word1 == 'enter' or word1 == 'walk') and word2:
#2800 'enter house' becomes simply 'house' and so forth
word1, word2 = word2, None
if ((word1 == 'water' or word1 == 'oil') and
(word2 == 'plant' or word2 == 'door') and
self.is_here(self.referent(word2))):
word1, word2 = self.vocabulary['pour'], word1
if word1 == 'say':
return self.t_say(word1, word2) if word2 else self.i_say(word1)
if word2 == 'say':
return self.t_say(word2, word1)
kinds = (word1.kind, word2.kind if word2 else None)
#2630
if kinds == ('travel', None):
if word1.text == 'west': #2610
self.full_wests += 1
if self.full_wests == 10:
self.write_message(17)
return self.do_motion(word1)
if kinds == ('snappy_comeback', None):
self.write_message(word1.n % 1000)
return self.finish_turn()
if kinds == ('noun', None):
verb, noun = None, word1
elif kinds == ('verb', None):
verb, noun = word1, None
elif kinds == ('verb', 'noun'):
verb, noun = word1, word2
elif kinds == ('noun', 'verb'):
noun, verb = word1, word2
else:
return self.dont_understand()
if not noun:
obj = None
else:
obj = self.referent(noun)
obj_here = self.is_here(obj)
if not obj_here:
if obj is self.grate:
if self.loc.n in (1, 4, 7):
return self.dispatch_command([ 'depression' ])
elif 9 < self.loc.n < 15:
return self.dispatch_command([ 'entrance' ])
elif noun == 'dwarf':
obj_here = any( d.room is self.loc for d in self.dwarves )
elif obj is self.bottle.contents and self.is_here(self.bottle):
obj_here = True
elif obj is self.loc.liquid:
obj_here = True
elif (obj is self.plant and self.is_here(self.plant2)
and self.plant2.prop != 0):
obj = self.plant2
obj_here = True
elif obj is self.knife and self.knife_location is self.loc:
self.knife_location = None
self.write_message(116)
return self.finish_turn()
elif obj is self.rod and self.is_here(self.rod2):
obj = self.rod2
obj_here = True
elif verb and (verb == 'find' or verb == 'inventory'):
obj_here = True # lie; these verbs work for absent objects
if not obj_here:
return self.i_see_no(noun)
if not verb:
self.write('What do you want to do with the {}?\n'.format(
noun.text))
return self.finish_turn()
verb_name = verb.synonyms[0].text
if obj:
method_name = 't_' + verb_name
args = (verb, obj)
else:
method_name = 'i_' + verb_name
args = (verb,)
method = getattr(self, method_name)
method(*args)
def dont_understand(self):
#3000 (a bit earlier than in the Fortran code)
n = self.random()
if n < 0.20: # 20% of the entire 1.0 range of random()
self.write_message(61)
elif n < 0.36: # 20% of the remaining 0.8 left
self.write_message(13)
else:
self.write_message(60)
self.finish_turn()
def i_see_no(self, thing):
self.write('I see no {} here.\n'.format(getattr(thing, 'text', thing)))
self.finish_turn()
# Motion.
def do_motion(self, word): #8
if word == 'null': #2
self.move_to()
return
elif word == 'back': #20
dest = self.oldloc2 if self.oldloc.is_forced else self.oldloc
self.oldloc2, self.oldloc = self.oldloc, self.loc
if dest is self.loc:
self.write_message(91)
self.move_to()
return
alt = None
for move in self.loc.travel_table:
if move.action is dest:
word = move.verbs[0] # arbitrary verb going to `dest`
break # Fall through, to attempt the move.
elif (isinstance(move.action, Room)
and move.action.is_forced
and move.action.travel_table[0].action is dest):
alt = move.verbs[0]
else: # no direct route is available
if alt is not None:
word = alt # take a forced move if it's the only option
else:
self.write_message(140)
self.move_to()
return
elif word == 'look': #30
if self.look_complaints > 0:
self.write_message(15)
self.look_complaints -= 1
self.loc.times_described = 0
self.move_to()
self.could_fall_in_pit = False
return
elif word == 'cave': #40
self.write_message(57 if self.loc.is_aboveground else 58)
self.move_to()
return
self.oldloc2, self.oldloc = self.oldloc, self.loc
for move in self.loc.travel_table:
if move.is_forced or word in move.verbs:
c = move.condition
if c[0] is None or c[0] == 'not_dwarf':
allowed = True
elif c[0] == '%':
allowed = 100 * self.random() < c[1]
elif c[0] == 'carrying':
allowed = self.objects[c[1]].is_toting
elif c[0] == 'carrying_or_in_room_with':
allowed = self.is_here(self.objects[c[1]])
elif c[0] == 'prop!=':
allowed = self.objects[c[1]].prop != c[2]
if not allowed:
continue
if isinstance(move.action, Room):
self.move_to(move.action)
return
elif isinstance(move.action, Message):
self.write(move.action)
self.move_to()
return
elif move.action == 301: #30100
inv = self.inventory
if len(inv) != 0 and inv != [ self.emerald ]:
self.write_message(117)
self.move_to()
elif self.loc.n == 100:
self.move_to(self.rooms[99])
else:
self.move_to(self.rooms[100])
return
elif move.action == 302: #30200
self.emerald.drop(self.loc)
self.do_motion(word)
return
elif move.action == 303: #30300
troll, troll2 = self.troll, self.troll2
if troll.prop == 1:
self.write(troll.messages[1])
troll.prop = 0
troll.rooms = list(troll.starting_rooms)
troll2.destroy()
self.move_to()
return
else:
places = list(troll.starting_rooms)
places.remove(self.loc)
self.loc = places[0] # "the other side of the bridge"
if troll.prop == 0:
troll.prop = 1
if not self.bear.is_toting:
self.move_to()
return
self.write_message(162)
self.chasm.prop = 1
troll.prop = 2
self.bear.drop(self.loc)
self.bear.is_fixed = True
self.bear.prop = 3
if self.spices.prop < 0:
self.impossible_treasures += 1
self.oldloc2 = self.loc # refuse to strand belongings
self.die()
return
#50
n = word.n
if 29 <= n <= 30 or 43 <= n <= 50:
self.write_message(9)
elif n in (7, 36, 37):
self.write_message(10)
elif n in (11, 19):
self.write_message(11)
elif n in (62, 65):
self.write_message(42)
elif n == 17:
self.write_message(80)
else:
self.write_message(12)
self.move_to()
return
# Death and reincarnation.
def die_here(self): #90
self.write_message(23)
self.oldloc2 = self.loc
self.die()
def die(self): #99
self.deaths += 1
self.is_dead = True
if self.is_closing:
self.write_message(131)
self.score_and_exit()
return
def callback(yes):
if yes:
self.write_message(80 + self.deaths * 2)
if self.deaths < self.max_deaths:
if self.bottle.contents is not None:
self.bottle.contents.hide()
self.is_dead = False
if self.lamp.is_toting:
self.lamp.prop = 0
for obj in self.inventory:
if obj is self.lamp:
obj.drop(self.rooms[1])
else:
obj.drop(self.oldloc2)
self.loc = self.rooms[3]
self.describe_location()
return
else:
self.write_message(54)
self.score_and_exit()
self.yesno(self.messages[79 + self.deaths * 2], callback)
# Verbs.
def ask_verb_what(self, verb, *args): #8000
self.write('{} What?\n'.format(verb.text))
self.finish_turn()
i_walk = ask_verb_what
i_drop = ask_verb_what
i_say = ask_verb_what
i_nothing = say_okay_and_finish
i_wave = ask_verb_what
i_calm = ask_verb_what
i_rub = ask_verb_what
i_throw = ask_verb_what
i_find = ask_verb_what
i_feed = ask_verb_what
i_break = ask_verb_what
i_wake = ask_verb_what
def write_default_message(self, verb, *args):
self.write(verb.default_message)
self.finish_turn()
t_nothing = say_okay_and_finish
t_calm = write_default_message
t_quit = write_default_message
t_score = write_default_message
t_fee = write_default_message
t_brief = write_default_message
t_hours = write_default_message
t_walk = write_default_message
def i_carry(self, verb): #8010
is_dwarf_here = any( dwarf.room == self.loc for dwarf in self.dwarves )
objs = self.objects_here
if len(objs) != 1 or is_dwarf_here:
self.ask_verb_what(verb)
else:
self.t_carry(verb, objs[0])
def t_carry(self, verb, obj): #9010
if obj.is_toting:
self.write(verb.default_message)
self.finish_turn()
return
if obj.is_fixed or len(obj.rooms) > 1:
if obj is self.plant and obj.prop <= 0:
self.write_message(115)
elif obj is self.bear and obj.prop == 1:
self.write_message(169)
elif obj is self.chain and self.chain.prop != 0:
self.write_message(170)
else:
self.write_message(25)
self.finish_turn()
return
if obj is self.water or obj is self.oil:
if self.is_here(self.bottle) and self.bottle.contents is obj:
# They want to carry the filled bottle.
obj = self.bottle
else:
# They must mean they want to fill the bottle.
if not self.bottle.is_toting:
self.write_message(104)
elif self.bottle.contents is not None:
self.write_message(105)
else:
self.t_fill(verb, self.bottle) # hand off control to "fill"
return
self.finish_turn()
return
if len(self.inventory) >= 7:
self.write_message(92)
self.finish_turn()
return
if obj is self.bird and obj.prop == 0:
if self.rod.is_toting:
self.write_message(26)
self.finish_turn(obj) # needs obj to decide to give hint
return
if not self.cage.is_toting:
self.write_message(27)
self.finish_turn()
return
self.bird.prop = 1
if (obj is self.bird or obj is self.cage) and self.bird.prop != 0:
self.bird.carry()
self.cage.carry()
else:
obj.carry()
if obj is self.bottle and self.bottle.contents is not None:
self.bottle.contents.carry()
self.say_okay_and_finish()
def t_drop(self, verb, obj): #9020
if obj is self.rod and not self.rod.is_toting and self.rod2.is_toting:
obj = self.rod2
if not obj.is_toting:
self.write(verb.default_message)
self.finish_turn()
return
bird, snake, dragon, bear, troll = self.bird, self.snake, self.dragon, \
self.bear, self.troll
if obj is bird and self.is_here(snake):
self.write_message(30)
if self.is_closed:
self.wake_repository_dwarves()
return
snake.prop = 1
snake.destroy()
elif obj is self.coins and self.is_here(self.machine):
obj.destroy()
self.batteries.drop(self.loc)
self.write(self.batteries.messages[0])
self.finish_turn()
return
elif obj is bird and self.is_here(dragon) and dragon.prop == 0:
self.write_message(154)
bird.destroy()
bird.prop = 0
if snake.rooms:
self.impossible_treasures += 1
self.finish_turn()
return
elif obj is bear and self.is_here(troll):
self.write_message(163)
troll.destroy()
self.troll2.rooms = list(self.troll.starting_rooms)
troll.prop = 2
elif obj is self.vase and self.loc is not self.rooms[96]:
if self.pillow.is_at(self.loc):
self.vase.prop = 0
else:
self.vase.prop = 2
self.vase.is_fixed = True
self.write(self.vase.messages[self.vase.prop + 1])
else:
self.write_message(54)
#9021
if obj is self.bottle.contents:
obj = self.bottle
if obj is self.bottle and self.bottle.contents:
self.bottle.contents.hide()
if obj is self.cage and self.bird.prop != 0:
bird.drop(self.loc)
elif obj is self.bird:
obj.prop = 0
obj.drop(self.loc)
self.finish_turn()
return
def t_say(self, verb, word): #9030
if word.n in (62, 65, 71, 2025):
self.dispatch_command([ word.text ])
else:
self.write('Okay, "{}".'.format(word.text))
self.finish_turn()
def i_unlock(self, verb): #8040 Handles "unlock" case as well
objs = (self.grate, self.door, self.oyster, self.clam, self.chain)
objs = list(filter(self.is_here, objs))
if len(objs) > 1:
self.ask_verb_what(verb)
elif len(objs) == 1:
self.t_unlock(verb, objs[0])
else:
self.write_message(28)
self.finish_turn()
i_lock = i_unlock
def t_unlock(self, verb, obj): #9040 Handles "lock" case as well
if obj is self.clam or obj is self.oyster:
#9046
oy = 1 if (obj is self.oyster) else 0
if verb == 'lock':
self.write_message(61)
elif not self.trident.is_toting:
self.write_message(122 + oy)
elif obj.is_toting:
self.write_message(120 + oy)
elif obj is self.oyster:
self.write_message(125)
else:
self.write_message(124)
self.clam.destroy()
self.oyster.drop(self.loc)
self.pearl.drop(self.rooms[105])
elif obj is self.door:
if obj.prop == 1:
self.write_message(54)
else:
self.write_message(111)
elif obj is self.cage:
self.write_message(32)
elif obj is self.keys:
self.write_message(55)
elif obj is self.grate or obj is self.chain:
if not self.is_here(self.keys):
self.write_message(31)
elif obj is self.chain:
#9048
if verb == 'unlock':
if self.chain.prop == 0:
self.write_message(37)
elif self.bear.prop == 0:
self.write_message(41)
else:
self.chain.prop = 0
self.chain.is_fixed = False
if self.bear.prop != 3:
self.bear.prop = 2
self.bear.is_fixed = 2 - self.bear.prop
self.write_message(171)
else:
#9049
if self.loc not in self.chain.starting_rooms:
self.write_message(173)
elif self.chain.prop != 0:
self.write_message(34)
else:
self.chain.prop = 2
if self.chain.is_toting:
self.chain.drop(self.loc)
self.chain.is_fixed = True
self.write_message(172)
elif self.is_closing:
if not self.panic:
self.clock2 = 15
self.panic = True
self.write_message(130)
else:
#9043
oldprop = obj.prop
obj.prop = 0 if verb == 'lock' else 1
self.write_message(34 + oldprop + 2 * obj.prop)
else:
self.write(verb.default_message)
self.finish_turn()
t_lock = t_unlock
def t_light(self, verb, obj=None): #9070
if not self.is_here(self.lamp):
self.write(verb.default_message)
elif self.lamp_turns <= 0:
self.write_message(184)
else:
self.lamp.prop = 1
self.write_message(39)
if self.loc.is_dark:
return self.describe_location()
self.finish_turn()
i_light = t_light
def t_extinguish(self, verb, obj=None): #9080
if not self.is_here(self.lamp):
self.write(verb.default_message)
else:
self.lamp.prop = 0
self.write_message(40)
if self.loc.is_dark:
self.write_message(16)
self.finish_turn()
i_extinguish = t_extinguish
def t_wave(self, verb, obj): #9090
fissure = self.fissure
if (obj is self.rod and obj.is_toting and self.is_here(fissure)
and not self.is_closing):
fissure.prop = 0 if fissure.prop else 1
self.write(fissure.messages[2 - fissure.prop])
else:
if obj.is_toting or (obj is self.rod and self.rod2.is_toting):
self.write(verb.default_message)
else:
self.write_message(29)
self.finish_turn()
def i_attack(self, verb): #9120
enemies = [ self.snake, self.dragon, self.troll, self.bear ]
if self.dwarf_stage >= 2:
enemies.extend(self.dwarves)
dangers = list(filter(self.is_here, enemies))
if len(dangers) > 1:
return self.ask_verb_what(verb)
if len(dangers) == 1:
return self.t_attack(verb, dangers[0])
targets = []
if self.is_here(self.bird) and verb != 'throw':
targets.append(self.bird)
if self.is_here(self.clam) or self.is_here(self.oyster):
targets.append(self.clam)
if len(targets) > 1:
return self.ask_verb_what(verb)
elif len(targets) == 1:
return self.t_attack(verb, targets[0])
else:
return self.t_attack(verb, None)
def t_attack(self, verb, obj): #9124 (but control goes to 9120 first)
if obj is self.bird:
if self.is_closed:
self.write_message(137)
else:
obj.destroy()
obj.prop = 0
if self.snake.rooms:
self.impossible_treasures += 1
self.write_message(45)
elif obj is self.clam or obj is self.oyster:
self.write_message(150)
elif obj is self.snake:
self.write_message(46)
elif obj is self.dwarf:
if self.is_closed:
self.wake_repository_dwarves()
return
self.write_message(49)
elif obj is self.dragon:
if self.dragon.prop != 0:
self.write_message(167)
else:
def callback(yes):
self.write(obj.messages[1])
obj.prop = 2
obj.is_fixed = True
oldroom1 = obj.rooms[0]
oldroom2 = obj.rooms[1]
newroom = self.rooms[ (oldroom1.n + oldroom2.n) // 2 ]
obj.drop(newroom)
self.rug.prop = 0
self.rug.is_fixed = False
self.rug.drop(newroom)
for oldroom in (oldroom1, oldroom2):
for o in self.objects_at(oldroom):
o.drop(newroom)
self.move_to(newroom)
self.yesno(self.messages[49], callback, casual=True)
return
elif obj is self.troll:
self.write_message(157)
elif obj is self.bear:
self.write_message(165 + (self.bear.prop + 1) // 2)
else:
self.write_message(44)
self.finish_turn()
def i_pour(self, verb): #9130
if self.bottle.contents is None:
self.ask_verb_what(verb)
else:
self.t_pour(verb, self.bottle.contents)
def t_pour(self, verb, obj):
if obj is self.bottle:
return self.i_pour(verb)
if not obj.is_toting:
self.write(verb.default_message)
elif obj is not self.oil and obj is not self.water:
self.write_message(78)
else:
self.bottle.prop = 1
self.bottle.contents = None
obj.hide()
if self.is_here(self.plant):
if obj is not self.water:
self.write_message(112)
else:
self.write(self.plant.messages[self.plant.prop + 1])
self.plant.prop = (self.plant.prop + 2) % 6
self.plant2.prop = self.plant.prop // 2
return self.move_to()
elif self.is_here(self.door):
#9132
self.door.prop = 1 if obj is self.oil else 0
self.write_message(113 + self.door.prop)
else:
self.write_message(77)
return self.finish_turn()
def i_eat(self, verb): #8140
if self.is_here(self.food):
self.t_eat(verb, self.food)
else:
self.ask_verb_what(verb)
def t_eat(self, verb, obj): #9140
if obj is self.food:
#8142
self.food.destroy()
self.write_message(72)
elif obj in (self.bird, self.snake, self.clam, self.oyster,
self.dwarf, self.dragon, self.troll, self.bear):
self.write_message(71)
else:
self.write(verb.default_message)
self.finish_turn()
def i_drink(self, verb): #9150
if self.is_here(self.water) or self.loc.liquid is self.water:
self.t_drink(verb, self.water)
else:
self.ask_verb_what(verb)
def t_drink(self, verb, obj): #9150
if obj is not self.water:
self.write_message(110)
elif self.is_here(self.water):
self.bottle.prop = 1
self.bottle.contents = None
self.water.destroy()
self.write_message(74)
elif self.loc.liquid is self.water:
self.write(verb.default_message)
self.finish_turn()
def t_rub(self, verb, obj): #9160
if obj is self.lamp:
self.write(verb.default_message)
else:
self.write_message(71)
self.finish_turn()
def t_throw(self, verb, obj): #9170
if obj is self.rod and not self.rod.is_toting and self.rod2.is_toting:
obj = self.rod2
if not obj.is_toting:
self.write(verb.default_message)
self.finish_turn()
return
if obj.is_treasure and self.is_here(self.troll):
# Pay the troll toll
self.write_message(159)
obj.destroy()
self.troll.destroy()
self.troll2.rooms = list(self.troll.starting_rooms)
self.finish_turn()
return
if obj is self.food and self.is_here(self.bear):
self.t_feed(verb, self.bear)
return
if obj is not self.axe:
self.t_drop(verb, obj)
return
dwarves_here = [ d for d in self.dwarves if d.room is self.loc ]
if dwarves_here:
# 1/3rd chance that throwing the axe kills a dwarf
if self.choice((True, False, False)):
self.dwarves.remove(dwarves_here[0])
self.dwarves_killed += 1
if self.dwarves_killed == 1:
self.write_message(149)
else:
self.write_message(47)
else:
self.write_message(48) # Miss
self.axe.drop(self.loc)
self.do_motion(self.vocabulary['null'])
return
if self.is_here(self.dragon) and self.dragon.prop == 0:
self.write_message(152)
self.axe.drop(self.loc)
self.do_motion(self.vocabulary['null'])
return
if self.is_here(self.troll):
self.write_message(158)
self.axe.drop(self.loc)
self.do_motion(self.vocabulary['null'])
return
if self.is_here(self.bear) and self.bear.prop == 0:
self.write_message(164)
self.axe.drop(self.loc)
self.axe.is_fixed = True
self.axe.prop = 1
self.finish_turn()
return
self.t_attack(verb, None)
def i_quit(self, verb): #8180
def callback(yes):
self.write_message(54)
if yes:
self.score_and_exit()
self.yesno(self.messages[22], callback)
def t_find(self, verb, obj): #9190
if obj.is_toting:
self.write_message(24)
elif self.is_closed:
self.write_message(138)
elif (self.is_here(obj) or
obj is self.loc.liquid or
obj is self.dwarf and any(d.room is self.loc for d in self.dwarves)):
self.write_message(94)
else:
self.write(verb.default_message)
self.finish_turn()
t_inventory = t_find
def i_inventory(self, verb): #8200
first = True
objs = [ obj for obj in self.inventory if obj is not self.bear ]
for obj in objs:
if first:
self.write_message(99)
first = False
self.write(obj.inventory_message)
if self.bear.is_toting:
self.write_message(141)
if not objs:
self.write_message(98)
self.finish_turn()
def t_feed(self, verb, obj): #9210
if obj is self.bird:
self.write_message(100)
elif obj is self.troll:
self.write_message(182)
elif obj is self.dragon:
if self.dragon.prop != 0:
self.write_message(110)
else:
self.write_message(102)
elif obj is self.snake:
if self.is_closed or not self.is_here(self.bird):
self.write_message(102)
else:
self.write_message(101)
self.bird.destroy()
self.bird.prop = 0
self.impossible_treasures += 1
elif obj is self.dwarf:
if self.is_here(self.food):
self.write_message(103)
self.dwarf_stage += 1
else:
self.write(verb.default_message)
elif obj is self.bear:
if not self.is_here(self.food):
if self.bear.prop == 0:
self.write_message(102)
elif self.bear.prop == 3:
self.write_message(110)
else:
self.write(verb.default_message)
else:
self.food.destroy()
self.bear.prop = 1
self.axe.is_fixed = False
self.axe.prop = 0
self.write_message(168)
else:
self.write_message(14)
self.finish_turn()
def i_fill(self, verb): #9220
if self.is_here(self.bottle):
return self.t_fill(verb, self.bottle)
self.ask_verb_what(verb)
def t_fill(self, verb, obj):
if obj is self.bottle:
liquid = self.loc.liquid
if liquid is None:
self.write_message(106)
elif self.bottle.contents:
self.write_message(105)
else:
self.bottle.contents = liquid
self.bottle.prop = 0 if (liquid is self.water) else 2
if self.bottle.is_toting:
liquid.is_toting = True
if liquid is self.oil:
self.write_message(108)
else:
self.write_message(107)
elif obj is self.vase:
#9222
if self.vase.is_toting:
if self.loc.liquid is None:
self.write_message(144)
else:
self.write_message(145)
self.vase.drop(self.loc)
self.vase.prop = 2
self.vase.is_fixed = True
else:
self.write(verb.default_message)
else:
self.write(verb.default_message)
self.finish_turn()
def t_blast(self, verb, obj=None): #9230
if self.rod2.prop < 0 or not self.is_closed:
self.write(verb.default_message)
self.finish_turn()
return
if self.is_here(self.rod2):
self.bonus = 135
elif self.loc.n == 115:
self.bonus = 134
else:
self.bonus = 133
self.write_message(self.bonus)
self.score_and_exit()
i_blast = t_blast
def i_score(self, verb): #8240
score, max_score = self.compute_score(for_score_command=True)
self.write('If you were to quit now, you would score {}'
' out of a possible {}.\n'.format(score, max_score))
def callback(yes):
self.write_message(54)
if yes:
self.score_and_exit()
self.yesno(self.messages[143], callback)
def i_fee(self, verb): #8250
for n in range(5):
if verb.synonyms[n].text == verb.text:
break # so that 0=fee, 1=fie, 2=foe, 3=foo, 4=fum
if n == 0:
self.foobar = self.turns
self.write_message(54)
elif n != self.turns - self.foobar:
self.write_message(151)
elif n < 3:
self.write_message(54)
else:
self.foobar = -1
eggs = self.eggs
start = eggs.starting_rooms[0]
if (eggs.is_at(start) or eggs.is_toting and self.loc is start):
self.write_message(54)
else:
troll = self.troll
if not eggs.rooms and not troll.rooms and not troll.prop:
self.troll.prop = 1
if self.loc is start:
self.write(eggs.messages[0])
elif self.is_here(eggs):
self.write(eggs.messages[1])
else:
self.write(eggs.messages[2])
eggs.rooms = list(eggs.starting_rooms)
eggs.is_toting = False
self.finish_turn()
def i_brief(self, verb): #8260
self.write_message(156)
self.full_description_period = 10000
self.look_complaints = 0
self.finish_turn()
def i_read(self, verb): #8270
if self.is_closed and self.oyster.is_toting:
return self.t_read(verb, self.oyster)
objs = (self.magazine, self.tablet, self.message)
objs = list(filter(self.is_here, objs))
if len(objs) != 1 or self.is_dark:
self.ask_verb_what(verb)
else:
self.t_read(verb, objs[0])
def t_read(self, verb, obj): #9270
if self.is_dark:
return self.i_see_no(obj.names[0])
elif (obj is self.oyster and not self.hints[2].used and
self.oyster.is_toting):
def callback(yes):
if yes:
self.hints[2].used = True
self.write_message(193)
else:
self.write_message(54)
self.yesno(self.messages[192], callback)
elif obj is self.oyster and self.hints[2].used:
self.write_message(194)
elif obj is self.message:
self.write_message(191)
elif obj is self.tablet:
self.write_message(196)
elif obj is self.magazine:
self.write_message(190)
else:
self.write(verb.default_message)
self.finish_turn()
def t_break(self, verb, obj): #9280
if obj is self.vase and self.vase.prop == 0:
self.write_message(198)
if self.vase.is_toting:
self.vase.drop(self.loc)
self.vase.prop = 2
self.vase.is_fixed = True
elif obj is self.mirror and self.is_closed:
self.write_message(197)
self.wake_repository_dwarves()
return
elif obj is self.mirror:
self.write_message(148)
else:
self.write(verb.default_message)
self.finish_turn()
def t_wake(self, verb, obj): #9290
if obj is self.dwarf and self.is_closed:
self.write_message(199)
self.wake_repository_dwarves()
else:
self.write(verb.default_message)
self.finish_turn()
def i_suspend(self, verb):
self.write('Provide "{}" with a filename or open file'.format(
verb.text))
self.finish_turn()
def t_suspend(self, verb, obj):
if isinstance(obj, str):
if os.path.exists(obj): # pragma: no cover
self.write('I refuse to overwrite an existing file.')
return
savefile = open(obj, 'wb')
else:
savefile = obj
r = self.random_generator # must replace live object with static state
self.random_state = r.getstate()
try:
del self.random_generator
savefile.write(zlib.compress(pickle.dumps(self), 9))
finally:
self.random_generator = r
if savefile is not obj:
savefile.close()
self.write('Game saved')
def i_hours(self, verb):
self.write('Open all day')
@classmethod
def resume(self, obj):
"""Returns an Adventure game saved to the given file."""
if isinstance(obj, str):
savefile = open(obj, 'rb')
else:
savefile = obj
game = pickle.loads(zlib.decompress(savefile.read()))
if savefile is not obj:
savefile.close()
# Reinstate the random number generator.
game.random_generator = random.Random()
game.random_generator.setstate(game.random_state)
del game.random_state
return game
def should_offer_hint(self, hint, obj): #40000
if hint.n == 4: # cave
return self.grate.prop == 0 and not self.is_here(self.keys)
elif hint.n == 5: # bird
bird = self.bird
return self.is_here(bird) and self.rod.is_toting and obj is bird
elif hint.n == 6: # snake
return self.is_here(self.snake) and not self.is_here(self.bird)
elif hint.n == 7: # maze
return (not len(self.objects_here) and
not len(self.objects_at(self.oldloc)) and
not len(self.objects_at(self.oldloc2)) and
len(self.inventory) > 1)
elif hint.n == 8: # dark
return self.emerald.prop != 1 and self.platinum.prop != 1
elif hint.n == 9: # witt
return True
def start_closing_cave(self): #10000
self.grate.prop = 0
self.fissure.prop = 0
del self.dwarves[:]
self.troll.destroy()
self.troll2.rooms = list(self.troll.starting_rooms)
if self.bear.prop != 3:
self.bear.destroy()
for obj in self.chain, self.axe:
obj.prop = 0
obj.is_fixed = False
self.write_message(129)
self.clock1 = -1
self.is_closing = True
def close_cave(self): #11000
ne = self.rooms[115] # ne end of repository
sw = self.rooms[116]
for obj in (self.bottle, self.plant, self.oyster, self.lamp,
self.rod, self.dwarf):
obj.prop = -2 if obj is self.bottle else -1
obj.drop(ne)
self.loc = self.oldloc = self.oldloc2 = ne
for obj in (self.grate, self.snake, self.bird, self.cage,
self.rod2, self.pillow):
obj.prop = -2 if (obj is self.bird or obj is self.snake) else -1
obj.drop(sw)
self.mirror.rooms = [ne, sw]
self.mirror.is_fixed = 1
self.is_closed = True
for obj in self.inventory:
obj.is_toting = False
self.write_message(132)
self.move_to()
# TODO: 12000
# TODO: 12200
# TODO: 12400
# TODO: 12600
def wake_repository_dwarves(self): #19000
self.write_message(136)
self.score_and_exit()
def compute_score(self, for_score_command=False): #20000
score = maxscore = 2
for treasure in self.treasures:
# if ptext(0) is zero?
if treasure.n > self.chest.n:
value = 16
elif treasure is self.chest:
value = 14
else:
value = 12
maxscore += value
if treasure.prop >= 0:
score += 2
if treasure.rooms and treasure.rooms[0].n == 3 \
and treasure.prop == 0:
score += value - 2
maxscore += self.max_deaths * 10
score += (self.max_deaths - self.deaths) * 10
maxscore += 4
if not for_score_command and not self.gave_up:
score += 4
maxscore += 25
if self.dwarf_stage:
score += 25
maxscore += 25
if self.is_closing:
score += 25
maxscore += 45
if self.is_closed:
score += {0: 10, 135: 25, 134: 30, 133: 45}[self.bonus]
maxscore += 1
if 108 in (room.n for room in self.magazine.rooms):
score += 1
for hint in list(self.hints.values()):
if hint.used:
score -= hint.penalty
return score, maxscore
def score_and_exit(self):
score, maxscore = self.compute_score()
self.write('\nYou scored {} out of a possible {} using {} turns.'
.format(score, maxscore, self.turns))
for i, (minimum, text) in enumerate(self.class_messages):
if minimum >= score:
break
self.write('\n{}\n'.format(text))
if i < len(self.class_messages) - 1:
d = self.class_messages[i+1][0] + 1 - score
self.write('To achieve the next higher rating, you need'
' {} more point{}\n'.format(d, 's' if d > 1 else ''))
else:
self.write('To achieve the next higher rating '
'would be a neat trick!\n\nCongratulations!!\n')
self.is_done = True
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1573219777.0
adventure-1.7/adventure/model.py 0000640 0001750 0001750 00000011442 13561266701 016722 0 ustar 00brandon brandon """Classes representing Adventure game components.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
class Move(object):
"""An entry in the travel table."""
is_forced = False
verbs = []
condition = None
action = None
def __repr__(self):
verblist = [ verb.text for verb in self.verbs ]
c = self.condition[0]
if c is None:
condition = ''
elif c == '%':
condition = ' %d%% of the time' % self.condition[1]
elif c == 'not_dwarf':
condition = ' if not a dwarf'
elif c == 'carrying':
condition = ' if carrying %s' % self.condition[1]
elif c == 'carrying_or_in_room_with':
condition = ' if carrying or in room with %s' % self.condition[1]
elif c == 'prop!=':
condition = ' if prop %d != %d' % self.condition[1:]
if isinstance(self.action, Room):
action = 'moves to %r' % (self.action.short_description
or self.action.long_description[:20]).strip()
elif isinstance(self.action, Message):
action = 'prints %r' % self.action.text
else:
action = 'special %d' % self.action
return '<{}{} {}>'.format('|'.join(verblist), condition, action)
class Room(object):
"""A location in the game."""
long_description = ''
short_description = ''
times_described = 0
visited = False
is_light = False
is_forbidden_to_pirate = False
liquid = None
trying_to_get_into_cave = False
trying_to_catch_bird = False
trying_to_deal_with_snake = False
lost_in_maze = False
pondering_dark_room = False
at_witts_end = False
def __init__(self):
self.travel_table = []
def __repr__(self):
return ''.format(self.n, hex(id(self)))
@property
def is_forced(self):
return self.travel_table and self.travel_table[0].is_forced
@property
def is_aboveground(self):
return 1 <= self.n <= 8
@property
def is_before_hall_of_mists(self):
return self.n < 15
@property
def is_after_hall_of_mists(self):
return self.n >= 15
@property
def is_dark(self):
return not self.is_light
class Word(object):
"""A word that can be used as part of a command."""
text = None
kind = None
default_message = None
def __init__(self):
self.synonyms = [ self ]
def __repr__(self):
return ''.format(self.text)
def __eq__(self, text):
return any( word.text == text for word in self.synonyms )
def add_synonym(self, other):
"""Every word in a group of synonyms shares the same list."""
self.synonyms.extend(other.synonyms)
other.synonyms = self.synonyms
class Object(object):
"""An object in the game, like a grate, or a rod with a rusty star."""
def __init__(self):
self.is_fixed = False
self.is_treasure = False
self.inventory_message = ''
self.messages = {}
self.names = []
self.prop = 0
self.rooms = []
self.starting_rooms = []
self.is_toting = False
self.contents = None # so the bottle can hold things
def __repr__(self):
return '