Showing preview only (303K chars total). Download the full file or copy to clipboard to get everything.
Repository: brandon-rhodes/python-adventure
Branch: master
Commit: fbe59584aea6
Files: 23
Total size: 291.5 KB
Directory structure:
gitextract_kuy29xws/
├── .gitignore
├── LICENSE.ASF-2
├── README.md
├── adventure/
│ ├── MANIFEST.in
│ ├── README.txt
│ ├── TODO.txt
│ ├── __init__.py
│ ├── __main__.py
│ ├── data.py
│ ├── game.py
│ ├── model.py
│ ├── prompt.py
│ └── tests/
│ ├── __init__.py
│ ├── syntax.txt
│ ├── test_commands.py
│ ├── test_data.py
│ ├── test_walks.py
│ ├── vignettes.txt
│ ├── walkthrough1.txt
│ ├── walkthrough2.txt
│ ├── walkthrough3.txt
│ └── walkthrough4.txt
└── setup.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.coverage
htmlcov/
*~
__pycache__/
*.pyc
/MANIFEST
build/
dist/
*.egg-info
================================================
FILE: LICENSE.ASF-2
================================================
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.
================================================
FILE: README.md
================================================
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)
================================================
FILE: adventure/MANIFEST.in
================================================
include LICENSE.*
================================================
FILE: adventure/README.txt
================================================
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.
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.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) <https://github.com/brandon-rhodes/python-adventure/issues/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
================================================
FILE: adventure/TODO.txt
================================================
* Test dropping into the secret canyon from the direction that gets no dragon.
================================================
FILE: adventure/__init__.py
================================================
"""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')
================================================
FILE: adventure/__main__.py
================================================
"""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))
if __name__ == '__main__':
try:
loop(sys.argv[1:])
except EOFError:
pass
================================================
FILE: adventure/data.py
================================================
# -*- 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 300<N<=500: N-300 is used in a computed GOTO to a
section of special code.
If N>500: 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<M<100: it is done with M% probability.
If M=100: unconditional, but forbidden to dwarves.
If 100<M<=200: he must be carrying object M-100.
If 200<M<=300: must be carrying or in same room as M-200.
If 300<M<=400: PROP(M MOD 100) must *not* be 0.
If 400<M<=500: PROP(M MOD 100) must *not* be 1.
If 500<M<=600: PROP(M MOD 100) must *not* be 2, etc.
If the condition (if any) is not met, then the next *different*
"destination" value is used (unless it fails to meet *its*
conditions, in which case the next is found, etc.). Typically, the
next dest will be for one of the same verbs, so that its only use is
as the alternate destination for those verbs. For instance:
15 110022 29 31 34 35 23 43
15 14 29
This says that, from LOC 15, any of the verbs 29, 31, etc., will
take him to 22 if he's carrying object 10, and otherwise will go to
14.
11 303008 49
11 9 50
This says that, from 11, 49 takes him to 8 unless PROP(3)=0, in
which case he goes to 9. Verb 50 takes him to 9 regardless of
PROP(3).
"""
last_travel = data._last_travel
if last_travel[0] == x and last_travel[1][0] == verbs[0]:
verbs = last_travel[1] # same first verb implies use whole list
else:
data._last_travel = [x, verbs]
m, n = divmod(y, 1000)
mh, mm = divmod(m, 100)
if m == 0:
condition = (None,)
elif 0 < m < 100:
condition = ('%', m)
elif m == 100:
condition = ('not_dwarf',)
elif 100 < m <= 200:
condition = ('carrying', mm)
elif 200 < m <= 300:
condition = ('carrying_or_in_room_with', mm)
elif 300 < m:
condition = ('prop!=', mm, mh - 3)
if n <= 300:
action = make_object(data.rooms, Room, n)
elif 300 < n <= 500:
action = n # special computed goto
else:
action = make_object(data.messages, Message, n - 500)
move = Move()
if len(verbs) == 1 and verbs[0] == 1:
move.is_forced = True
else:
move.verbs = [ make_object(data.vocabulary, Word, verb_n)
for verb_n in verbs if verb_n < 100 ] # skip bad "109"
move.condition = condition
move.action = action
data.rooms[x].travel_table.append(move)
def section4(data, n, text, *etc):
"""Handle record from “Section 4: vocabulary”.
Section 4: vocabulary. Each line contains a number (N), a TAB, and a
five-letter word. Call M=N/1000. If M=0, then the word is a motion
verb for use in travelling (see section 3). Else, if M=1, the word
is an object. Else, if M=2, the word is an action verb (such as
"CARRY" or "ATTACK"). Else, if M=3, the word is a special case verb
(such as "DIG") and N MOD 1000 is an index into section 6. Objects
from 50 to (currently, anyway) 79 are considered treasures (for
pirate, closeout).
"""
text = text.lower()
text = long_words.get(text, text)
word = make_object(data.vocabulary, Word, n)
if word.text is None: # this is the first word with index "n"
word.text = text
else: # there is already a word sitting at "n", so create a synonym
original = word
word = Word()
word.n = n
word.text = text
original.add_synonym(word)
word.kind = ['travel', 'noun', 'verb', 'snappy_comeback'][n // 1000]
if word.kind == 'noun':
n %= 1000
obj = make_object(data.objects, Object, n)
obj.names.append(text)
obj.is_treasure = (n >= 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
================================================
FILE: adventure/game.py
================================================
"""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
================================================
FILE: adventure/model.py
================================================
"""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 '<room {} at {}>'.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 '<Word {}>'.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 '<Object %d %s %x>' % (self.n, '/'.join(self.names), id(self))
def __hash__(self):
return self.n
def __eq__(self, other):
return any( text == other for text in self.names )
def is_at(self, room):
return room in self.rooms
def carry(self):
self.rooms[:] = []
self.is_toting = True
def drop(self, room):
self.rooms[:] = [ room ]
self.is_toting = False
def hide(self):
self.rooms[:] = []
self.is_toting = False
def destroy(self):
self.hide()
class Message(object):
"""A message for printing."""
text = ''
def __str__(self):
return self.text
class Hint(object):
"""A hint offered if the player loiters in one area too long."""
turns_needed = 0
turn_counter = 0
penalty = 0
question = None
message = None
used = False
def __init__(self):
self.rooms = []
class Dwarf(object):
is_dwarf = True
is_pirate = False
def __init__(self, room):
self.start_at(room)
self.has_seen_adventurer = False
def start_at(self, room):
self.room = room
self.old_room = room
def can_move(self, move):
if not isinstance(move.action, Room):
return False
room = move.action
return (room.is_after_hall_of_mists
and not room.is_forced
and not move.condition == ('%', 100))
class Pirate(Dwarf):
is_dwarf = False
is_pirate = True
================================================
FILE: adventure/prompt.py
================================================
"""Routines that install Adventure commands for the Python 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 inspect
class ReprTriggeredPhrase(object):
"""Command that happens when Python calls repr() to print them."""
def __init__(self, game, words):
self.game = game
self.words = tuple(words) # protect against caller changing list
def __repr__(self):
"""Run this command and return the message that results."""
output = self.game.do_command(self.words)
return output.rstrip('\n') + '\n'
def __call__(self, arg=None):
"""Return a compound command of several words, like `get(keys)`."""
if arg is None:
return self
words = arg.words if isinstance(arg, ReprTriggeredPhrase) else (arg,)
return ReprTriggeredPhrase(self.game, self.words + words)
def __getattr__(self, name):
return ReprTriggeredPhrase(self.game, self.words + (name,))
def install_words(game):
# stack()[0] is this; stack()[1] is adventure.play(); so, stack()[2]
namespace = inspect.stack()[2][0].f_globals
words = [ k for k in game.vocabulary if isinstance(k, str) ]
words.append('yes')
words.append('no')
for word in words:
identifier = ReprTriggeredPhrase(game, [ word ])
namespace[word] = identifier
if len(word) > 5:
namespace[word[:5]] = identifier
================================================
FILE: adventure/tests/__init__.py
================================================
================================================
FILE: adventure/tests/syntax.txt
================================================
>>> import adventure
>>> adventure.play(seed=2)
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
<BLANKLINE>
>>> 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.
<BLANKLINE>
>>> brief
OKAY, FROM NOW ON I'LL ONLY DESCRIBE A PLACE IN FULL THE FIRST TIME
YOU COME TO IT. TO GET THE FULL DESCRIPTION, SAY "LOOK".
<BLANKLINE>
This doctest exercises all of the different ways that people try to
invoke Adventure commands from the Python prompt.
Simple movement can be invoked simply by typing the direction, but some
players will try to call them as functions instead.
>>> s
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
<BLANKLINE>
>>> n()
YOU'RE AT END OF ROAD AGAIN.
<BLANKLINE>
That pretty much exhausts the possibilities when a word is being used
alone as a command. But when two words are being combined, there are
several different ways that they might be called!
One word can be used as a function and the second as an argument:
>>> goto(building)
YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS A SHINY BRASS LAMP NEARBY.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
Or, a period can be used to separate the words. Note that nouns and
verbs can be in either order.
>>> get.keys
OK
<BLANKLINE>
>>> lamp.get
OK
<BLANKLINE>
Why do we support putting the noun and verb in either order? Because
some users think of verbs as methods supported by the game's nouns, and
will format their commands like method calls:
>>> food.get()
OK
<BLANKLINE>
================================================
FILE: adventure/tests/test_commands.py
================================================
"""Test suite.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
from unittest import TestCase
from adventure import load_advent_dat
from adventure.game import Game
class CommandTest(TestCase):
def setUp(self):
game = Game()
load_advent_dat(game)
self.words = set(w.synonyms[0].text for w in game.vocabulary.values())
self.words.remove('suspend')
def test_intransitive_commands_should_not_throw_exceptions(self):
for word in self.words:
game = Game()
load_advent_dat(game)
game.start()
game.do_command(['no']) # WOULD YOU LIKE INSTRUCTIONS?
game.do_command([word])
def test_transitive_commands_should_not_throw_exceptions(self):
for word in self.words:
game = Game()
load_advent_dat(game)
game.start()
game.do_command(['no']) # WOULD YOU LIKE INSTRUCTIONS?
game.do_command(['enter']) # so we are next to lamp
game.do_command([word, 'lamp'])
================================================
FILE: adventure/tests/test_data.py
================================================
"""Test suite.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
import unittest
class DataTest(unittest.TestCase):
def setUp(self):
from adventure.data import Data
from adventure import load_advent_dat
self.data = Data()
load_advent_dat(self.data)
def test_long_description(self):
self.assertEqual(self.data.rooms[4].long_description, """\
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
""")
def test_long_description_expands_tabs(self):
self.assertIn("ALMOST AS IF ALIVE. A COLD WIND BLOWS",
self.data.rooms[15].long_description)
def test_short_description(self):
self.assertEqual(self.data.rooms[4].short_description,
"YOU'RE IN VALLEY.\n")
def test_object_message_expands_tabs(self):
self.assertEqual(self.data.objects[24].messages[5], """\
YOU'VE OVER-WATERED THE PLANT! IT'S SHRIVELING UP! IT'S, IT'S...
""")
def test_hint(self):
hint = self.data.hints[4]
self.assertEqual(hint.turns_needed, 4)
self.assertEqual(hint.penalty, 2)
self.assertEqual(hint.question.text,
"ARE YOU TRYING TO GET INTO THE CAVE?\n")
self.assertEqual(hint.message.text, """\
THE GRATE IS VERY SOLID AND HAS A HARDENED STEEL LOCK. YOU CANNOT
ENTER WITHOUT A KEY, AND THERE ARE NO KEYS NEARBY. I WOULD RECOMMEND
LOOKING ELSEWHERE FOR THE KEYS.
""")
class ReprTest(unittest.TestCase):
def setUp(self):
from adventure.data import Data
from adventure import load_advent_dat
self.data = Data()
load_advent_dat(self.data)
def assertMove(self, room_i, entry_i, s):
r = repr(self.data.rooms[room_i].travel_table[entry_i]).strip()
self.assertEqual(r, s)
def test_move_repr_look_good(self):
m = self.assertMove
m(1, 0, '<road|west|upward moves to "YOU\'RE AT HILL IN ROAD.">')
m(108, 0, '<east|north|south|ne|se|sw|nw|upward|d 95% of the time'
' prints \'YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND'
' UP BACK IN THE\\nMAIN PASSAGE.\\n\'>')
m(61, 2, '<south if not a dwarf moves to \'YOU ARE IN A MAZE OF\'>')
m(15, 3, '<upward|pit|steps|dome|passage|east if carrying 50 moves'
' to \'THE DOME IS UNCLIMBA\'>')
m(19, 6, '<sw if carrying or in room with 11 moves to '
'"YOU CAN\'T GET BY THE">')
m(17, 2, '<forward if prop 12 != 1 moves to "YOU DIDN\'T MAKE IT.">')
def test_move_repr_works_on_all_moves(self):
for room in self.data.rooms.values():
for i, move in enumerate(room.travel_table):
try:
repr(move)
except: # pragma: no cover
print(room, i)
raise
def test_room_repr(self):
self.assertRegex(repr(self.data.rooms[64]), '<room 64 at .*>')
def test_object_repr(self):
self.assertRegex(repr(self.data.objects['chest']),
r'<Object 55 chest/box/treasure .*>')
def test_word_repr(self):
self.assertEqual(repr(self.data.vocabulary['eat']), '<Word eat>')
================================================
FILE: adventure/tests/test_walks.py
================================================
"""Test suite.
Copyright 2010-2015 Brandon Rhodes. Licensed as free software under the
Apache License, Version 2.0 as detailed in the accompanying README.txt.
"""
import doctest
import os
import shutil
import tempfile
def load_tests(loader, tests, pattern):
cd = ChdirTemp()
tests.addTests(doctest.DocFileSuite(
'../README.txt', optionflags=doctest.NORMALIZE_WHITESPACE,
setUp=cd.setup, tearDown=cd.teardown))
tests.addTests(doctest.DocFileSuite('syntax.txt'))
tests.addTests(doctest.DocFileSuite('vignettes.txt'))
tests.addTests(doctest.DocFileSuite('walkthrough1.txt'))
tests.addTests(doctest.DocFileSuite('walkthrough2.txt'))
tests.addTests(doctest.DocFileSuite('walkthrough3.txt'))
return tests
class ChdirTemp(object):
def setup(self, doctest_object):
self.old_directory = os.getcwd()
self.tmp_directory = tempfile.mkdtemp()
os.chdir(self.tmp_directory)
def teardown(self, doctest_object):
os.chdir(self.old_directory)
shutil.rmtree(self.tmp_directory)
================================================
FILE: adventure/tests/vignettes.txt
================================================
>>> import io
>>> from itertools import cycle, islice
This file tests the behavior of the Adventure game in all sorts of
specific situations that would be very tedious to arrange in actual
walkthroughs. As the basis for these tests, we will begin by starting a
game, entering the building, and carrying the lamp.
>>> import adventure
>>> adventure.play(seed=3)
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
<BLANKLINE>
>>> 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.
<BLANKLINE>
>>> brief
OKAY, FROM NOW ON I'LL ONLY DESCRIBE A PLACE IN FULL THE FIRST TIME
YOU COME TO IT. TO GET THE FULL DESCRIPTION, SAY "LOOK".
<BLANKLINE>
>>> enter
YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS A SHINY BRASS LAMP NEARBY.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> on
YOUR LAMP IS NOW ON.
<BLANKLINE>
>>> get(lamp)
OK
<BLANKLINE>
>>> for _room in adventure._game.rooms.values():
... _room.times_described = 1 # to avoid long descriptions
Now we can save this game.
>>> savefile = io.BytesIO()
>>> save(savefile)
GAME SAVED
<BLANKLINE>
Now, all of the tests below can begin by calling this restart() function
to place them back at the beginning of the adventure in a known state.
If a room is specified, note that restart() performs two turns in the
room before handing back control: the first when it asks the game to
move the caller into that room, and the second when it calls look().
>>> def restart(room=None, dwarves=False, objects=(), randoms=None):
... """Restart the whole Adventure game from our stringio file."""
...
... global game
... savefile.seek(0)
... adventure.resume(savefile, quiet=True)
... game = adventure._game
... if room is not None:
... _go_to(room)
... room = game.loc
... if not dwarves:
... game.dwarf_stage = 2
... del game.dwarves[:]
... for obj in objects:
... if isinstance(obj, adventure.prompt.ReprTriggeredPhrase):
... obj = game.referent(game.vocabulary[obj.words[0]])
... obj.drop(room)
... if randoms is not None:
... game.random = list(randoms).pop
>>> class go_to(object):
... """Special command that warps us directly to a location."""
...
... def __init__(self, room):
... self.room = room
... def __repr__(self):
... game.output = ''
... _go_to(self.room)
... return game.output.rstrip('\n') + '\n'
>>> def _go_to(room):
... game.move_to(game.rooms[room] if isinstance(room, int) else room)
>>> def quiet(*args):
... """Run one or more commands without printing their result."""
...
... for arg in args:
... repr(arg)
... return None
With those definitions complete, we can proceed with the actual tests!
---------------------------------------
You Won't Get It Down The Steps, Either
---------------------------------------
>>> restart(room=18)
>>> look
THIS IS A LOW ROOM WITH A CRUDE NOTE ON THE WALL. THE NOTE SAYS,
"YOU WON'T GET IT UP THE STEPS".
<BLANKLINE>
THERE IS A LARGE SPARKLING NUGGET OF GOLD HERE!
<BLANKLINE>
>>> get(gold)
OK
<BLANKLINE>
>>> go_to(13)
YOU'RE IN BIRD CHAMBER.
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> w
YOU'RE AT TOP OF SMALL PIT.
<BLANKLINE>
>>> d
YOU ARE AT THE BOTTOM OF THE PIT WITH A BROKEN NECK.
<BLANKLINE>
OH DEAR, YOU SEEM TO HAVE GOTTEN YOURSELF KILLED. I MIGHT BE ABLE TO
HELP YOU OUT, BUT I'VE NEVER REALLY DONE THIS BEFORE. DO YOU WANT ME
TO TRY TO REINCARNATE YOU?
<BLANKLINE>
THE TROLL IS NOWHERE TO BE SEEN.
<BLANKLINE>
>>> n
OK
<BLANKLINE>
<BLANKLINE>
YOU SCORED 53 OUT OF A POSSIBLE 350 USING 9 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 78 MORE POINTS
<BLANKLINE>
>>> look
YOU HAVE GOTTEN YOURSELF KILLED.
<BLANKLINE>
-------------------
Pirates and dwarves
-------------------
If the dwarves activate when we are standing in one of their starting
rooms, then does the dwarf at our location get moved successfully to the
gold nuggets room?
>>> restart(room=41, dwarves=True, randoms=[None, .9, .9, .99])
>>> [ _dwarf.room.n for _dwarf in game.dwarves ]
[19, 27, 33, 44, 64]
>>> e
A LITTLE DWARF JUST WALKED AROUND A CORNER, SAW YOU, THREW A LITTLE
AXE AT YOU WHICH MISSED, CURSED, AND RAN AWAY.
<BLANKLINE>
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
THERE ARE DIAMONDS HERE!
<BLANKLINE>
>>> [ _dwarf.room.n for _dwarf in game.dwarves ]
[19, 18, 33, 44, 64]
If the pirate encounters us in the plover room or dark room, does he
leave the platinum pyramid since learning how to remove it from the room
is one of the game's puzzles?
>>> restart(room=100, objects=[pyramid])
>>> look
YOU'RE IN A SMALL CHAMBER LIT BY AN EERIE GREEN LIGHT. AN EXTREMELY
NARROW TUNNEL EXITS TO THE WEST. A DARK CORRIDOR LEADS NE.
<BLANKLINE>
THERE IS AN EMERALD HERE THE SIZE OF A PLOVER'S EGG!
<BLANKLINE>
THERE IS A PLATINUM PYRAMID HERE, 8 INCHES ON A SIDE!
<BLANKLINE>
>>> get(pyramid)
OK
<BLANKLINE>
>>> get(emerald)
OK
<BLANKLINE>
>>> game.pirate.room = game.loc
>>> look
OUT FROM THE SHADOWS BEHIND YOU POUNCES A BEARDED PIRATE! "HAR, HAR,"
HE CHORTLES, "I'LL JUST TAKE ALL THIS BOOTY AND HIDE IT AWAY WITH ME
CHEST DEEP IN THE MAZE!" HE SNATCHES YOUR TREASURE AND VANISHES INTO
THE GLOOM.
<BLANKLINE>
YOU'RE IN A SMALL CHAMBER LIT BY AN EERIE GREEN LIGHT. AN EXTREMELY
NARROW TUNNEL EXITS TO THE WEST. A DARK CORRIDOR LEADS NE.
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
BRASS LANTERN
PLATINUM PYRAMID
<BLANKLINE>
If we manage to collect all of the treasures before the pirate spots us,
then when we find him he goes to hide his treasure chest in the maze
without any other treasures to accompany it.
>>> restart()
>>> for t in game.treasures:
... if t == 'chest': continue
... t.drop(game.loc)
>>> quiet(look)
>>> game.dwarf_stage = 2
>>> game.loc = game.pirate.room = game.rooms[69]
>>> look
THERE ARE FAINT RUSTLING NOISES FROM THE DARKNESS BEHIND YOU. AS YOU
TURN TOWARD THEM, THE BEAM OF YOUR LAMP FALLS ACROSS A BEARDED PIRATE.
HE IS CARRYING A LARGE CHEST. "SHIVER ME TIMBERS!" HE CRIES, "I'VE
BEEN SPOTTED! I'D BEST HIE MESELF OFF TO THE MAZE TO HIDE ME CHEST!"
WITH THAT, HE VANISHES INTO THE GLOOM.
<BLANKLINE>
YOU ARE IN A SECRET N/S CANYON ABOVE A LARGE ROOM.
<BLANKLINE>
>>> go_to(game.chest_room)
DEAD END
<BLANKLINE>
THE PIRATE'S TREASURE CHEST IS HERE!
<BLANKLINE>
If several dwarves throw knives that hit us, does a sensible message result?
>>> restart(room=75, dwarves=True, randoms=(.05,.05,.05,.05,.05,.05))
>>> game.dwarf_stage = 3
>>> for _dwarf in game.dwarves:
... _dwarf.room = game.rooms[75]
>>> look
THERE ARE 5 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
5 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
5 OF THEM GET YOU!
<BLANKLINE>
OH DEAR, YOU SEEM TO HAVE GOTTEN YOURSELF KILLED. I MIGHT BE ABLE TO
HELP YOU OUT, BUT I'VE NEVER REALLY DONE THIS BEFORE. DO YOU WANT ME
TO TRY TO REINCARNATE YOU?
<BLANKLINE>
If, when a treasure is found, the game figures out that all remaining
treasures are impossible to acquire - like the jewelry in the south side
chamber of the Hall of the Mountain King, if the bird dies before the
snake is driven away - then the lamp should be reduced to only having 35
turns left.
>>> restart()
>>> for t in game.treasures:
... if t == 'jewelry' or t == 'silver': continue
... t.drop(game.loc)
>>> quiet(look)
>>> game.bird.carry()
>>> go_to(119)
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
A HUGE GREEN FIERCE DRAGON BARS THE WAY!
<BLANKLINE>
>>> drop(bird)
THE LITTLE BIRD ATTACKS THE GREEN DRAGON, AND IN AN ASTOUNDING FLURRY
GETS BURNT TO A CINDER. THE ASHES BLOW AWAY.
<BLANKLINE>
>>> game.lamp_turns
326
>>> go_to(28)
YOU ARE IN A LOW N/S PASSAGE AT A HOLE IN THE FLOOR. THE HOLE GOES
DOWN TO AN E/W PASSAGE.
<BLANKLINE>
THERE ARE BARS OF SILVER HERE!
<BLANKLINE>
>>> game.lamp_turns
35
We should not be able to pick up a dwarf! (#21)
>>> restart(room=75, dwarves=True, randoms=(1,.05,.05,.05,.05,.05,.3))
>>> game.dwarf_stage = 3
>>> game.dwarves[0].room = game.rooms[75]
>>> take(dwarf)
YOU CAN'T BE SERIOUS!
<BLANKLINE>
----------------------------------
Making sure that hints are offered
----------------------------------
If you act confused, the game should offer you a hint. Here are quick
(but certainly not thorough!) tests of whether the logic for each hint
allows it to be offered.
>>> restart(room=8)
>>> quiet(look, look)
>>> look
YOU ARE IN A 20-FOOT DEPRESSION FLOORED WITH BARE DIRT. SET INTO THE
DIRT IS A STRONG STEEL GRATE MOUNTED IN CONCRETE. A DRY STREAMBED
LEADS INTO THE DEPRESSION.
<BLANKLINE>
THE GRATE IS LOCKED.
<BLANKLINE>
ARE YOU TRYING TO GET INTO THE CAVE?
<BLANKLINE>
>>> yes
THE GRATE IS VERY SOLID AND HAS A HARDENED STEEL LOCK. YOU CANNOT
ENTER WITHOUT A KEY, AND THERE ARE NO KEYS NEARBY. I WOULD RECOMMEND
LOOKING ELSEWHERE FOR THE KEYS.
<BLANKLINE>
>>> restart(room=13, objects=[rod])
>>> quiet(get(rod), look, look)
>>> get(bird)
THE BIRD WAS UNAFRAID WHEN YOU ENTERED, BUT AS YOU APPROACH IT BECOMES
DISTURBED AND YOU CANNOT CATCH IT.
<BLANKLINE>
ARE YOU TRYING TO CATCH THE BIRD?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> restart(room=19)
>>> quiet(*[ look ] * 6)
>>> look
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
A HUGE GREEN FIERCE SNAKE BARS THE WAY!
<BLANKLINE>
ARE YOU TRYING TO SOMEHOW DEAL WITH THE SNAKE?
<BLANKLINE>
>>> restart(room=42, objects=[food])
>>> quiet(get(food), s, n)
>>> quiet(*islice(cycle((w, s, n)), 75 - 5))
>>> look
YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.
<BLANKLINE>
DO YOU NEED HELP GETTING OUT OF THE MAZE?
<BLANKLINE>
>>> yes
YOU CAN MAKE THE PASSAGES LOOK LESS ALIKE BY DROPPING THINGS.
<BLANKLINE>
>>> quiet(restart(room=99))
>>> quiet([ look ] * (25 - 2))
>>> look
YOU ARE IN AN ALCOVE. A SMALL NW PATH SEEMS TO WIDEN AFTER A SHORT
DISTANCE. AN EXTREMELY TIGHT TUNNEL LEADS EAST. IT LOOKS LIKE A VERY
TIGHT SQUEEZE. AN EERIE LIGHT CAN BE SEEN AT THE OTHER END.
<BLANKLINE>
ARE YOU TRYING TO EXPLORE BEYOND THE PLOVER ROOM?
<BLANKLINE>
>>> quiet(restart(room=108), [ look ] * (20 - 2))
>>> look
YOU ARE AT WITT'S END. PASSAGES LEAD OFF IN *ALL* DIRECTIONS.
<BLANKLINE>
DO YOU NEED HELP GETTING OUT OF HERE?
<BLANKLINE>
------------------------
Your lamp is getting dim
------------------------
There is an elaborate set of messages generated for the player as their
lamp starts to grow dim. You can, of course, replentish the lamp using
batteries from the vending machine in the maze.
>>> quiet(restart(room=34))
>>> game.chest.prop = 1
>>> quiet([ look ] * (330 - 30 - 3))
>>> look
YOUR LAMP IS GETTING DIM. YOU'D BEST START WRAPPING THIS UP, UNLESS
YOU CAN FIND SOME FRESH BATTERIES. I SEEM TO RECALL THERE'S A VENDING
MACHINE IN THE MAZE. BRING SOME COINS WITH YOU.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> quiet(go_to(30), get(coins))
>>> go_to(140)
DEAD END
<BLANKLINE>
THERE IS A MASSIVE VENDING MACHINE HERE. THE INSTRUCTIONS ON IT READ:
"DROP COINS HERE TO RECEIVE FRESH BATTERIES."
<BLANKLINE>
>>> drop(coins)
THERE ARE FRESH BATTERIES HERE.
<BLANKLINE>
>>> look
YOUR LAMP IS GETTING DIM. I'M TAKING THE LIBERTY OF REPLACING THE
BATTERIES.
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A MASSIVE VENDING MACHINE HERE. THE INSTRUCTIONS ON IT READ:
"DROP COINS HERE TO RECEIVE FRESH BATTERIES."
<BLANKLINE>
SOME WORN-OUT BATTERIES HAVE BEEN DISCARDED NEARBY.
<BLANKLINE>
>>> game.lamp_turns = 31
>>> n
YOUR LAMP IS GETTING DIM, AND YOU'RE OUT OF SPARE BATTERIES. YOU'D
BEST START WRAPPING THIS UP.
<BLANKLINE>
YOU ARE IN A LITTLE MAZE OF TWISTING PASSAGES, ALL DIFFERENT.
<BLANKLINE>
>>> game.lamp_turns = 1
>>> n
YOUR LAMP HAS RUN OUT OF POWER.
<BLANKLINE>
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> go_to(5)
YOU'RE IN FOREST.
<BLANKLINE>
>>> w
THERE'S NOT MUCH POINT IN WANDERING AROUND OUT HERE, AND YOU CAN'T
EXPLORE THE CAVE WITHOUT A LAMP. SO LET'S JUST CALL IT A DAY.
<BLANKLINE>
<BLANKLINE>
YOU SCORED 61 OUT OF A POSSIBLE 350 USING 309 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 70 MORE POINTS
<BLANKLINE>
If the batteries are in the user's inventory when replaced, then the old
ones are tossed on the ground rather than remaining in the inventory.
>>> restart(room=30)
>>> quiet(get(coins), go_to(140), drop(coins))
>>> get(batteries)
OK
<BLANKLINE>
>>> game.chest.prop = 1
>>> game.lamp_turns = 30
>>> look
YOUR LAMP IS GETTING DIM. I'M TAKING THE LIBERTY OF REPLACING THE
BATTERIES.
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A MASSIVE VENDING MACHINE HERE. THE INSTRUCTIONS ON IT READ:
"DROP COINS HERE TO RECEIVE FRESH BATTERIES."
<BLANKLINE>
SOME WORN-OUT BATTERIES HAVE BEEN DISCARDED NEARBY.
<BLANKLINE>
Finally, if you leave the batteries in the maze, you are warned to go
back and get them.
>>> quiet(restart(room=34), go_to(30), get(coins), go_to(140), drop(coins), n)
>>> game.lamp_turns = 30
>>> look
YOUR LAMP IS GETTING DIM. YOU'D BEST GO BACK FOR THOSE BATTERIES.
<BLANKLINE>
YOU ARE IN A LITTLE MAZE OF TWISTING PASSAGES, ALL DIFFERENT.
<BLANKLINE>
----------------------------------
Basic and advanced command parsing
----------------------------------
Various complaints are associated with poorly-chosen requests.
>>> quiet(restart(room=34))
>>> enter(water)
WHERE?
<BLANKLINE>
>>> quiet(go_to(7))
>>> enter(water)
YOUR FEET ARE NOW WET.
<BLANKLINE>
You can try to enter the house with the 'enter' command instead of just
naming the house.
>>> quiet(restart(room=1))
>>> enter(house)
YOU'RE INSIDE BUILDING.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
Both "oil" and "water" can be used as verbs, despite officially being
treated as nouns in the game vocabulary.
>>> restart(room=94)
>>> look
YOU ARE AT ONE END OF AN IMMENSE NORTH/SOUTH PASSAGE.
<BLANKLINE>
THE WAY NORTH IS BARRED BY A MASSIVE, RUSTY, IRON DOOR.
<BLANKLINE>
>>> oil(door)
I SEE NO OIL HERE.
<BLANKLINE>
>>> go_to(25)
YOU'RE IN WEST PIT.
<BLANKLINE>
THERE IS A TINY LITTLE PLANT IN THE PIT, MURMURING "WATER, WATER, ..."
<BLANKLINE>
>>> water(plant)
I SEE NO WATER HERE.
<BLANKLINE>
Various combinations of words yield somewhat sensible retorts; and
several nouns invoke small special cases in the code, like "grate" also
being a movement noun.
>>> restart(room=4, dwarves=True)
>>> look
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
<BLANKLINE>
>>> game.do_command(['eat', 'pray', 'love'])
"I DON'T KNOW THAT WORD.\n\n"
>>> grate
YOU'RE OUTSIDE GRATE.
<BLANKLINE>
THE GRATE IS LOCKED.
<BLANKLINE>
>>> go_to(12)
YOU ARE IN AN AWKWARD SLOPING EAST/WEST CANYON.
<BLANKLINE>
>>> grate
YOU'RE BELOW THE GRATE.
<BLANKLINE>
THE GRATE IS LOCKED.
<BLANKLINE>
>>> carry(dwarf)
I SEE NO DWARF HERE.
<BLANKLINE>
>>> quiet(go_to(3))
>>> get(water)
OK
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
BRASS LANTERN
SMALL BOTTLE
WATER IN THE BOTTLE
<BLANKLINE>
>>> get(knife)
I SEE NO KNIFE HERE.
<BLANKLINE>
>>> game.dwarf_stage = 2
>>> go_to(27)
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE ARE DIAMONDS HERE!
<BLANKLINE>
>>> get(knife)
THE DWARVES' KNIVES VANISH AS THEY STRIKE THE WALLS OF THE CAVE.
<BLANKLINE>
>>> get(knife)
I SEE NO KNIFE HERE.
<BLANKLINE>
>>> find(jewelry)
I CAN ONLY TELL YOU WHAT YOU SEE AS YOU MOVE ABOUT AND MANIPULATE
THINGS. I CANNOT TELL YOU WHERE REMOTE THINGS ARE.
<BLANKLINE>
>>> lamp
WHAT DO YOU WANT TO DO WITH THE LAMP?
<BLANKLINE>
>>> quiet(restart(randoms=(None, 0.1, None, 0.3, None, 0.9)))
>>> carry(pour)
I DON'T KNOW THAT WORD.
<BLANKLINE>
>>> jump(eat)
I DON'T UNDERSTAND THAT!
<BLANKLINE>
>>> throw(drop)
WHAT?
<BLANKLINE>
---------------
Special motions
---------------
The "back" movement command has to handle several special cases, in case
the previous location was an intermediate "forced" room, or if it simply
cannot figure out how to return you to the previous location.
>>> quiet(restart(room=65, randoms=(None, None, 0.001,)))
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU ARE IN BEDQUILT, A LONG EAST/WEST PASSAGE WITH HOLES EVERYWHERE.
TO EXPLORE AT RANDOM SELECT NORTH, SOUTH, UP, OR DOWN.
<BLANKLINE>
>>> back
SORRY, BUT I NO LONGER SEEM TO REMEMBER HOW IT WAS YOU GOT HERE.
<BLANKLINE>
YOU ARE IN BEDQUILT, A LONG EAST/WEST PASSAGE WITH HOLES EVERYWHERE.
TO EXPLORE AT RANDOM SELECT NORTH, SOUTH, UP, OR DOWN.
<BLANKLINE>
While testing "back" on the beanstalk, we also test for whether we can
run a command like "get" on the plant as seen from outside the pits.
>>> quiet(restart(), get(bottle), go_to(25), pour(water))
>>> quiet(go_to(113), get(water), go_to(25), pour(water))
>>> go_to(88)
YOU'RE IN NARROW CORRIDOR.
<BLANKLINE>
>>> d
YOU'RE IN WEST PIT.
<BLANKLINE>
THERE IS A GIGANTIC BEANSTALK STRETCHING ALL THE WAY UP TO THE HOLE.
<BLANKLINE>
>>> back
YOU CLAMBER UP THE PLANT AND SCURRY THROUGH THE HOLE AT THE TOP.
<BLANKLINE>
YOU'RE IN NARROW CORRIDOR.
<BLANKLINE>
>>> go_to(23)
YOU'RE AT WEST END OF TWOPIT ROOM.
<BLANKLINE>
THERE IS A HUGE BEANSTALK GROWING OUT OF THE WEST PIT UP TO THE HOLE.
<BLANKLINE>
>>> find(beanstalk)
I BELIEVE WHAT YOU WANT IS RIGHT HERE WITH YOU.
<BLANKLINE>
>>> go_to(67)
YOU'RE AT EAST END OF TWOPIT ROOM.
<BLANKLINE>
THERE IS A HUGE BEANSTALK GROWING OUT OF THE WEST PIT UP TO THE HOLE.
<BLANKLINE>
>>> go_to(91)
YOU'RE AT STEEP INCLINE ABOVE LARGE ROOM.
<BLANKLINE>
>>> d
YOU ARE IN A LARGE LOW ROOM. CRAWLS LEAD NORTH, SE, AND SW.
<BLANKLINE>
>>> back
YOU CAN'T GET THERE FROM HERE.
<BLANKLINE>
YOU ARE IN A LARGE LOW ROOM. CRAWLS LEAD NORTH, SE, AND SW.
<BLANKLINE>
If the player tries walking back across the troll bridge while still
carrying the bear, then disaster strikes: the bridge breaks beneath
them, and both player and bear wind up dead at the bottom of the pit.
But the game shows a bit of elegance, and refuses to strand the player's
belongings out of reach, either at the pit bottom or where they were
last standing on the far side of the troll bridge - since without the
bridge, the items would be permanently lost! (We also try feeding the
bear a few times, to test some special cases in the feed() logic while
we are at it.)
>>> quiet(restart(), get(keys), go_to(123))
>>> game.bear.carry()
>>> game.bear.prop = 2
>>> game.bear.is_fixed = False
>>> w
YOU ARE BEING FOLLOWED BY A VERY LARGE, TAME BEAR.
<BLANKLINE>
YOU'RE ON NE SIDE OF CHASM.
<BLANKLINE>
A RICKETY WOODEN BRIDGE EXTENDS ACROSS THE CHASM, VANISHING INTO THE
MIST. A SIGN POSTED ON THE BRIDGE READS, "STOP! PAY TROLL!"
<BLANKLINE>
A BURLY TROLL STANDS BY THE BRIDGE AND INSISTS YOU THROW HIM A
TREASURE BEFORE YOU MAY CROSS.
<BLANKLINE>
>>> drop(bear)
THE BEAR LUMBERS TOWARD THE TROLL, WHO LETS OUT A STARTLED SHRIEK AND
SCURRIES AWAY. THE BEAR SOON GIVES UP THE PURSUIT AND WANDERS BACK.
<BLANKLINE>
>>> feed(bear)
THERE IS NOTHING HERE TO EAT.
<BLANKLINE>
>>> get(bear)
OK
<BLANKLINE>
>>> sw
JUST AS YOU REACH THE OTHER SIDE, THE BRIDGE BUCKLES BENEATH THE
WEIGHT OF THE BEAR, WHICH WAS STILL FOLLOWING YOU AROUND. YOU
SCRABBLE DESPERATELY FOR SUPPORT, BUT AS THE BRIDGE COLLAPSES YOU
STUMBLE BACK AND FALL INTO THE CHASM.
<BLANKLINE>
OH DEAR, YOU SEEM TO HAVE GOTTEN YOURSELF KILLED. I MIGHT BE ABLE TO
HELP YOU OUT, BUT I'VE NEVER REALLY DONE THIS BEFORE. DO YOU WANT ME
TO TRY TO REINCARNATE YOU?
<BLANKLINE>
>>> quiet(yes, leave, get(lamp), on)
>>> go_to(117)
YOU'RE ON SW SIDE OF CHASM.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THE WRECKAGE OF A BRIDGE (AND A DEAD BEAR) CAN BE SEEN AT THE BOTTOM
OF THE CHASM.
<BLANKLINE>
THE TROLL IS NOWHERE TO BE SEEN.
<BLANKLINE>
>>> feed(bear)
DON'T BE RIDICULOUS!
<BLANKLINE>
Several motion words elicit special messages when they do not apply.
>>> quiet(restart(room=34))
>>> onward
I AM UNSURE HOW YOU ARE FACING. USE COMPASS POINTS OR NEARBY OBJECTS.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> left
I AM UNSURE HOW YOU ARE FACING. USE COMPASS POINTS OR NEARBY OBJECTS.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> right
I AM UNSURE HOW YOU ARE FACING. USE COMPASS POINTS OR NEARBY OBJECTS.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> leave
I DON'T KNOW IN FROM OUT HERE. USE COMPASS POINTS OR NAME SOMETHING
IN THE GENERAL DIRECTION YOU WANT TO GO.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> inward
I DON'T KNOW IN FROM OUT HERE. USE COMPASS POINTS OR NAME SOMETHING
IN THE GENERAL DIRECTION YOU WANT TO GO.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> xyzzy
NOTHING HAPPENS.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> plugh
NOTHING HAPPENS.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> crawl
WHICH WAY?
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
---------------
Verb edge cases
---------------
And now, we exercise dozens of fiddly edge cases for verbs.
>>> quiet(restart())
>>> carry # ambiguous in the face of several objects
CARRY WHAT?
<BLANKLINE>
>>> quiet(restart(room=25))
>>> get(plant)
THE PLANT HAS EXCEPTIONALLY DEEP ROOTS AND CANNOT BE PULLED FREE.
<BLANKLINE>
>>> quiet(restart(), go_to(24))
>>> get(oil)
YOU HAVE NOTHING IN WHICH TO CARRY IT.
<BLANKLINE>
>>> quiet(go_to(3), get(bottle), go_to(24))
>>> get(oil)
YOUR BOTTLE IS ALREADY FULL.
<BLANKLINE>
>>> get(bottle)
YOU ARE ALREADY CARRYING IT!
<BLANKLINE>
>>> drop(oil)
YOU AREN'T CARRYING IT!
<BLANKLINE>
>>> drop(water)
OK
<BLANKLINE>
>>> look
YOU ARE AT THE BOTTOM OF THE EASTERN PIT IN THE TWOPIT ROOM. THERE IS
A SMALL POOL OF OIL IN ONE CORNER OF THE PIT.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> restart(room=94, objects=[clam])
>>> look
YOU ARE AT ONE END OF AN IMMENSE NORTH/SOUTH PASSAGE.
<BLANKLINE>
THE WAY NORTH IS BARRED BY A MASSIVE, RUSTY, IRON DOOR.
<BLANKLINE>
THERE IS AN ENORMOUS CLAM HERE WITH ITS SHELL TIGHTLY CLOSED.
<BLANKLINE>
>>> unlock # two unlockable objects are present
UNLOCK WHAT?
<BLANKLINE>
>>> quiet(s)
>>> unlock # no unlockable objects also cause a problem
THERE IS NOTHING HERE WITH A LOCK!
<BLANKLINE>
>>> restart(room=103, objects=[trident])
>>> lock(clam)
WHAT?
<BLANKLINE>
>>> quiet(get(clam), get(trident))
>>> unlock
I ADVISE YOU TO PUT DOWN THE CLAM BEFORE OPENING IT. >STRAIN!<
<BLANKLINE>
>>> quiet(drop(clam))
>>> unlock
A GLISTENING PEARL FALLS OUT OF THE CLAM AND ROLLS AWAY. GOODNESS,
THIS MUST REALLY BE AN OYSTER. (I NEVER WAS VERY GOOD AT IDENTIFYING
BIVALVES.) WHATEVER IT IS, IT HAS NOW SNAPPED SHUT AGAIN.
<BLANKLINE>
>>> unlock
THE OYSTER CREAKS OPEN, REVEALING NOTHING BUT OYSTER INSIDE. IT
PROMPTLY SNAPS SHUT AGAIN.
<BLANKLINE>
>>> restart(room=94)
>>> look
YOU ARE AT ONE END OF AN IMMENSE NORTH/SOUTH PASSAGE.
<BLANKLINE>
THE WAY NORTH IS BARRED BY A MASSIVE, RUSTY, IRON DOOR.
<BLANKLINE>
>>> unlock
THE DOOR IS EXTREMELY RUSTY AND REFUSES TO OPEN.
<BLANKLINE>
>>> restart()
>>> unlock(keys)
YOU CAN'T UNLOCK THE KEYS.
<BLANKLINE>
>>> quiet(get(keys), get(food), go_to(10))
>>> unlock(cage)
IT HAS NO LOCK.
<BLANKLINE>
>>> quiet(go_to(130))
>>> lock(chain)
IT WAS ALREADY LOCKED.
<BLANKLINE>
>>> unlock(chain)
THERE IS NO WAY TO GET PAST THE BEAR TO UNLOCK THE CHAIN, WHICH IS
PROBABLY JUST AS WELL.
<BLANKLINE>
>>> quiet(throw(food), unlock(chain))
>>> unlock(chain)
IT WAS ALREADY UNLOCKED.
<BLANKLINE>
>>> quiet(get(chain), w)
>>> lock(chain)
THERE IS NOTHING HERE TO WHICH THE CHAIN CAN BE LOCKED.
<BLANKLINE>
>>> quiet(e)
>>> lock(chain)
THE CHAIN IS NOW LOCKED.
<BLANKLINE>
>>> get(chain)
THE CHAIN IS STILL LOCKED.
<BLANKLINE>
>>> lock(bear)
I DON'T KNOW HOW TO LOCK OR UNLOCK SUCH A THING.
<BLANKLINE>
>>> restart()
>>> off
YOUR LAMP IS NOW OFF.
<BLANKLINE>
>>> quiet(drop(lamp), leave)
>>> on
YOU HAVE NO SOURCE OF LIGHT.
<BLANKLINE>
>>> off
YOU HAVE NO SOURCE OF LIGHT.
<BLANKLINE>
>>> quiet(enter, get(lamp), on, plugh)
>>> off
YOUR LAMP IS NOW OFF.
<BLANKLINE>
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> quiet(on)
>>> game.lamp_turns = 2
>>> quiet(look)
>>> look
YOUR LAMP HAS RUN OUT OF POWER.
<BLANKLINE>
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> on
YOUR LAMP HAS RUN OUT OF POWER.
<BLANKLINE>
>>> restart()
>>> wave(lamp)
NOTHING HAPPENS.
<BLANKLINE>
>>> wave(keys)
YOU AREN'T CARRYING IT!
<BLANKLINE>
The "attack" verb is a particularly long test, because its intransitive
form works hard to determine - in two stages, focusing first on real
enemies and then on some harmless objects - what on earth you could
possibly be designating as a target.
>>> restart(dwarves=True)
>>> attack
THERE IS NOTHING HERE TO ATTACK.
<BLANKLINE>
>>> quiet(go_to(117))
>>> attack
TROLLS ARE CLOSE RELATIVES WITH THE ROCKS AND HAVE SKIN AS TOUGH AS
THAT OF A RHINOCEROS. THE TROLL FENDS OFF YOUR BLOWS EFFORTLESSLY.
<BLANKLINE>
>>> game.dwarf_stage = 2
>>> game.dwarves[0].room = game.loc
>>> attack # now there are two choices: dwarf and troll
ATTACK WHAT?
<BLANKLINE>
>>> attack(dwarf)
WITH WHAT? YOUR BARE HANDS?
<BLANKLINE>
>>> quiet(go_to(103), get(clam), go_to(13))
>>> attack # cannot decide between oyster and bird
ATTACK WHAT?
<BLANKLINE>
>>> quiet(w, drop(clam), e)
>>> attack
THE LITTLE BIRD IS NOW DEAD. ITS BODY DISAPPEARS.
<BLANKLINE>
>>> look # make sure the bird is really gone
YOU ARE IN A SPLENDID CHAMBER THIRTY FEET HIGH. THE WALLS ARE FROZEN
RIVERS OF ORANGE STONE. AN AWKWARD CANYON AND A GOOD PASSAGE EXIT
FROM EAST AND WEST SIDES OF THE CHAMBER.
<BLANKLINE>
>>> quiet(w)
>>> attack
THE SHELL IS VERY STRONG AND IS IMPERVIOUS TO ATTACK.
<BLANKLINE>
>>> quiet(go_to(119))
>>> attack(dragon)
WITH WHAT? YOUR BARE HANDS?
<BLANKLINE>
>>> quiet(yes)
>>> attack(dragon)
FOR CRYING OUT LOUD, THE POOR THING IS ALREADY DEAD!
<BLANKLINE>
>>> quiet(restart(), get(bottle))
>>> pour
YOUR BOTTLE IS EMPTY AND THE GROUND IS WET.
<BLANKLINE>
>>> pour
POUR WHAT?
<BLANKLINE>
>>> quiet(go_to(24), get(oil), go_to(25))
>>> pour(bottle)
THE PLANT INDIGNANTLY SHAKES THE OIL OFF ITS LEAVES AND ASKS, "WATER?"
<BLANKLINE>
>>> quiet(go_to(24), get(oil))
>>> pour
YOUR BOTTLE IS EMPTY AND THE GROUND IS WET.
<BLANKLINE>
>>> pour(oil)
YOU AREN'T CARRYING IT!
<BLANKLINE>
>>> pour(lamp)
YOU CAN'T POUR THAT.
<BLANKLINE>
>>> restart()
>>> eat
THANK YOU, IT WAS DELICIOUS!
<BLANKLINE>
>>> eat
EAT WHAT?
<BLANKLINE>
>>> quiet(go_to(13))
>>> eat(bird)
I THINK I JUST LOST MY APPETITE.
<BLANKLINE>
>>> quiet(e, e)
>>> eat(rod)
DON'T BE RIDICULOUS!
<BLANKLINE>
>>> quiet(restart(), get(bottle), leave, w)
>>> drink
THE BOTTLE OF WATER IS NOW EMPTY.
<BLANKLINE>
>>> drink
DRINK WHAT?
<BLANKLINE>
>>> drink(lamp)
DON'T BE RIDICULOUS!
<BLANKLINE>
>>> quiet(restart())
>>> rub(lamp)
RUBBING THE ELECTRIC LAMP IS NOT PARTICULARLY REWARDING. ANYWAY,
NOTHING EXCITING HAPPENS.
<BLANKLINE>
>>> rub(bottle)
I THINK I JUST LOST MY APPETITE.
<BLANKLINE>
>>> quiet(restart(objects=[axe]), get(axe))
>>> throw(food)
YOU AREN'T CARRYING IT!
<BLANKLINE>
>>> quiet(get(food), leave)
>>> throw(lamp)
OK
<BLANKLINE>
>>> look
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.
<BLANKLINE>
THERE IS A LAMP SHINING NEARBY.
<BLANKLINE>
>>> quiet(get(lamp), go_to(130))
>>> throw(axe)
THE AXE MISSES AND LANDS NEAR THE BEAR WHERE YOU CAN'T GET AT IT.
<BLANKLINE>
>>> get(axe)
YOU CAN'T BE SERIOUS!
<BLANKLINE>
>>> throw(food)
THE BEAR EAGERLY WOLFS DOWN YOUR FOOD, AFTER WHICH HE SEEMS TO CALM
DOWN CONSIDERABLY AND EVEN BECOMES RATHER FRIENDLY.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> quiet(leave)
>>> throw(axe)
THERE IS NOTHING HERE TO ATTACK.
<BLANKLINE>
>>> restart()
>>> quit()
DO YOU REALLY WANT TO QUIT NOW?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> quit()
DO YOU REALLY WANT TO QUIT NOW?
<BLANKLINE>
>>> yes
OK
<BLANKLINE>
<BLANKLINE>
YOU SCORED 61 OUT OF A POSSIBLE 350 USING 7 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 70 MORE POINTS
<BLANKLINE>
>>> restart()
>>> find(lamp)
YOU ARE ALREADY CARRYING IT!
<BLANKLINE>
>>> find(keys)
I BELIEVE WHAT YOU WANT IS RIGHT HERE WITH YOU.
<BLANKLINE>
>>> quiet(restart(), get(food), get(keys), go_to(130), throw(food), unlock)
>>> get(bear)
OK
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
YOU ARE BEING FOLLOWED BY A VERY LARGE, TAME BEAR.
<BLANKLINE>
>>> quiet(restart(dwarves=True), go_to(10), get(cage), go_to(13))
>>> feed(bird)
IT'S NOT HUNGRY (IT'S MERELY PININ' FOR THE FJORDS). BESIDES, YOU
HAVE NO BIRD SEED.
<BLANKLINE>
>>> quiet(get(bird), go_to(117))
>>> feed(troll)
GLUTTONY IS NOT ONE OF THE TROLL'S VICES. AVARICE, HOWEVER, IS.
<BLANKLINE>
>>> quiet(go_to(119))
>>> feed(dragon)
THERE'S NOTHING HERE IT WANTS TO EAT (EXCEPT PERHAPS YOU).
<BLANKLINE>
>>> quiet(kill(dragon), yes)
>>> feed(dragon)
DON'T BE RIDICULOUS!
<BLANKLINE>
>>> quiet(go_to(19))
>>> feed(snake)
THE SNAKE HAS NOW DEVOURED YOUR BIRD.
<BLANKLINE>
>>> feed(snake)
THERE'S NOTHING HERE IT WANTS TO EAT (EXCEPT PERHAPS YOU).
<BLANKLINE>
>>> game.dwarf_stage = 2
>>> quiet(look)
>>> feed(dwarf)
THERE IS NOTHING HERE TO EAT.
<BLANKLINE>
>>> game.food.drop(game.loc)
>>> feed(dwarf)
YOU FOOL, DWARVES EAT ONLY COAL! NOW YOU'VE MADE HIM *REALLY* MAD!!
<BLANKLINE>
>>> quiet(go_to(129), drop(food), e)
>>> feed(bear)
THERE'S NOTHING HERE IT WANTS TO EAT (EXCEPT PERHAPS YOU).
<BLANKLINE>
>>> feed(chain)
I'M GAME. WOULD YOU CARE TO EXPLAIN HOW?
<BLANKLINE>
>>> quiet(restart(), get(bottle), drink)
>>> fill
YOUR BOTTLE IS NOW FULL OF WATER.
<BLANKLINE>
>>> fill
YOUR BOTTLE IS ALREADY FULL.
<BLANKLINE>
>>> quiet(drink, plugh)
>>> fill
THERE IS NOTHING HERE WITH WHICH TO FILL THE BOTTLE.
<BLANKLINE>
>>> quiet(drop(bottle), go_to(97))
>>> fill(vase)
YOU CAN'T FILL THAT.
<BLANKLINE>
>>> quiet(get(vase))
>>> fill(vase)
THERE IS NOTHING HERE WITH WHICH TO FILL THE VASE.
<BLANKLINE>
>>> quiet(go_to(38))
>>> fill(vase)
THE SUDDEN CHANGE IN TEMPERATURE HAS DELICATELY SHATTERED THE VASE.
<BLANKLINE>
>>> look
YOU ARE IN THE BOTTOM OF A SMALL PIT WITH A LITTLE STREAM, WHICH
ENTERS AND EXITS THROUGH TINY SLITS.
<BLANKLINE>
THE FLOOR IS LITTERED WITH WORTHLESS SHARDS OF POTTERY.
<BLANKLINE>
>>> get(vase)
YOU CAN'T BE SERIOUS!
<BLANKLINE>
>>> fill(lamp)
YOU CAN'T FILL THAT.
<BLANKLINE>
>>> fill
FILL WHAT?
<BLANKLINE>
>>> restart()
>>> blast
BLASTING REQUIRES DYNAMITE.
<BLANKLINE>
>>> restart()
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 57 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> yes
OK
<BLANKLINE>
<BLANKLINE>
YOU SCORED 61 OUT OF A POSSIBLE 350 USING 6 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 70 MORE POINTS
<BLANKLINE>
>>> quiet(restart(), go_to(92), fee, fie, foe)
>>> foo # does nothing obvious since the eggs are here
OK
<BLANKLINE>
>>> quiet(get(eggs), go_to(117))
>>> throw(eggs)
THE TROLL CATCHES YOUR TREASURE AND SCURRIES AWAY OUT OF SIGHT.
<BLANKLINE>
>>> quiet(fee, fie, foe)
>>> foo
DONE!
<BLANKLINE>
>>> cross # troll does not wait for us to cross!
THE TROLL STEPS OUT FROM BENEATH THE BRIDGE AND BLOCKS YOUR WAY.
<BLANKLINE>
YOU'RE ON SW SIDE OF CHASM.
<BLANKLINE>
A RICKETY WOODEN BRIDGE EXTENDS ACROSS THE CHASM, VANISHING INTO THE
MIST. A SIGN POSTED ON THE BRIDGE READS, "STOP! PAY TROLL!"
<BLANKLINE>
A BURLY TROLL STANDS BY THE BRIDGE AND INSISTS YOU THROW HIM A
TREASURE BEFORE YOU MAY CROSS.
<BLANKLINE>
>>> quiet(restart(), go_to(106))
>>> read
I'M AFRAID THE MAGAZINE IS WRITTEN IN DWARVISH.
<BLANKLINE>
>>> quiet(off)
>>> read(magazine)
I SEE NO MAGAZINE HERE.
<BLANKLINE>
>>> quiet(on, get(magazine), go_to(101))
>>> read # confused by two choices
READ WHAT?
<BLANKLINE>
>>> read(tablet)
"CONGRATULATIONS ON BRINGING LIGHT INTO THE DARK-ROOM!"
<BLANKLINE>
>>> quiet(go_to(95), get(trident), go_to(103), unlock(clam), get(oyster))
>>> read(oyster)
HMMM, THIS LOOKS LIKE A CLUE, WHICH MEANS IT'LL COST YOU 10 POINTS TO
READ IT. SHOULD I GO AHEAD AND READ IT ANYWAY?
<BLANKLINE>
>>> yes
IT SAYS, "THERE IS SOMETHING STRANGE ABOUT THIS PLACE, SUCH THAT ONE
OF THE WORDS I'VE ALWAYS KNOWN NOW HAS A NEW EFFECT."
<BLANKLINE>
>>> read(oyster)
IT SAYS THE SAME THING IT DID BEFORE.
<BLANKLINE>
>>> quiet(go_to(29), get(gold), go_to(112))
>>> game.pirate.room = game.rooms[112]
>>> look
OUT FROM THE SHADOWS BEHIND YOU POUNCES A BEARDED PIRATE! "HAR, HAR,"
HE CHORTLES, "I'LL JUST TAKE ALL THIS BOOTY AND HIDE IT AWAY WITH ME
CHEST DEEP IN THE MAZE!" HE SNATCHES YOUR TREASURE AND VANISHES INTO
THE GLOOM.
<BLANKLINE>
YOU ARE IN A LITTLE MAZE OF TWISTING PASSAGES, ALL DIFFERENT.
<BLANKLINE>
>>> s
DEAD END
<BLANKLINE>
THERE IS A MESSAGE SCRAWLED IN THE DUST IN A FLOWERY SCRIPT, READING:
"THIS IS NOT THE MAZE WHERE THE PIRATE LEAVES HIS TREASURE CHEST."
<BLANKLINE>
THERE IS A MASSIVE VENDING MACHINE HERE. THE INSTRUCTIONS ON IT READ:
"DROP COINS HERE TO RECEIVE FRESH BATTERIES."
<BLANKLINE>
>>> read(message)
"THIS IS NOT THE MAZE WHERE THE PIRATE LEAVES HIS TREASURE CHEST."
<BLANKLINE>
>>> read(lamp)
I'M AFRAID I DON'T UNDERSTAND.
<BLANKLINE>
>>> quiet(restart(), go_to(97))
>>> smash(vase)
YOU HAVE TAKEN THE VASE AND HURLED IT DELICATELY TO THE GROUND.
<BLANKLINE>
>>> get(vase)
YOU CAN'T BE SERIOUS!
<BLANKLINE>
>>> quiet(restart(), go_to(97))
>>> get(vase) # can we also break it while carrying it?
OK
<BLANKLINE>
>>> smash(vase)
YOU HAVE TAKEN THE VASE AND HURLED IT DELICATELY TO THE GROUND.
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
BRASS LANTERN
<BLANKLINE>
>>> look
THIS IS THE ORIENTAL ROOM. ANCIENT ORIENTAL CAVE DRAWINGS COVER THE
WALLS. A GENTLY SLOPING PASSAGE LEADS UPWARD TO THE NORTH, ANOTHER
PASSAGE LEADS SE, AND A HANDS AND KNEES CRAWL LEADS WEST.
<BLANKLINE>
THE FLOOR IS LITTERED WITH WORTHLESS SHARDS OF POTTERY.
<BLANKLINE>
>>> quiet(go_to(109))
>>> smash(mirror)
IT IS TOO FAR UP FOR YOU TO REACH.
<BLANKLINE>
>>> smash(lamp)
IT IS BEYOND YOUR POWER TO DO THAT.
<BLANKLINE>
>>> quiet(restart())
>>> wake(keys)
DON'T BE RIDICULOUS!
<BLANKLINE>
>>> quiet(restart())
>>> suspend
PROVIDE "SUSPEND" WITH A FILENAME OR OPEN FILE
<BLANKLINE>
----------------
Closing the cave
----------------
Finally, there are a few situations we need to test that relate
specifically to the end-game. For example, dying while the cave is
closing causes a very abrupt ending to the game.
>>> quiet(restart(), drop(lamp), go_to(13))
>>> game.is_closing = 1
>>> game.start_closing_cave()
>>> w
YOU FELL INTO A PIT AND BROKE EVERY BONE IN YOUR BODY!
<BLANKLINE>
IT LOOKS AS THOUGH YOU'RE DEAD. WELL, SEEING AS HOW IT'S SO CLOSE TO
CLOSING TIME ANYWAY, I THINK WE'LL JUST CALL IT A DAY.
<BLANKLINE>
<BLANKLINE>
YOU SCORED 78 OUT OF A POSSIBLE 350 USING 7 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 53 MORE POINTS
<BLANKLINE>
Now we reload our saved game one last time, take it through the ending,
and then save anew so that we can do several tests in the repository.
>>> quiet(restart(), get(keys), go_to(9))
>>> game.is_closing = 1
>>> game.start_closing_cave()
>>> unlock
A MYSTERIOUS RECORDED VOICE GROANS INTO LIFE AND ANNOUNCES:
"THIS EXIT IS CLOSED. PLEASE LEAVE VIA MAIN OFFICE."
<BLANKLINE>
>>> game.clock2 = 1
>>> w
THE SEPULCHRAL VOICE ENTONES, "THE CAVE IS NOW CLOSED." AS THE ECHOES
FADE, THERE IS A BLINDING FLASH OF LIGHT (AND A SMALL PUFF OF ORANGE
SMOKE). . . . AS YOUR EYES REFOCUS, YOU LOOK AROUND AND FIND...
<BLANKLINE>
YOU'RE AT NE END.
<BLANKLINE>
>>> quiet(savefile.truncate())
>>> savefile.seek(0)
0
>>> save(savefile)
GAME SAVED
<BLANKLINE>
Most of the interesting end-game events are fatal, but not all.
>>> quiet(restart(), sw)
>>> get(cage)
OK
<BLANKLINE>
>>> attack(bird)
OH, LEAVE THE POOR UNHAPPY BIRD ALONE.
<BLANKLINE>
>>> drop(bird)
THE LITTLE BIRD ATTACKS THE GREEN SNAKE, AND IN AN ASTOUNDING FLURRY
DRIVES THE SNAKE AWAY.
<BLANKLINE>
THE RESULTING RUCKUS HAS AWAKENED THE DWARVES. THERE ARE NOW SEVERAL
THREATENING LITTLE DWARVES IN THE ROOM WITH YOU! MOST OF THEM THROW
KNIVES AT YOU! ALL OF THEM GET YOU!
<BLANKLINE>
<BLANKLINE>
YOU SCORED 98 OUT OF A POSSIBLE 350 USING 13 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 33 MORE POINTS
<BLANKLINE>
>>> quiet(restart())
>>> attack(dwarf)
THE RESULTING RUCKUS HAS AWAKENED THE DWARVES. THERE ARE NOW SEVERAL
THREATENING LITTLE DWARVES IN THE ROOM WITH YOU! MOST OF THEM THROW
KNIVES AT YOU! ALL OF THEM GET YOU!
<BLANKLINE>
<BLANKLINE>
YOU SCORED 98 OUT OF A POSSIBLE 350 USING 10 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 33 MORE POINTS
<BLANKLINE>
>>> quiet(restart(), sw)
>>> get(rod) # grab the rusty-mark rod
OK
<BLANKLINE>
>>> ne # move to where the rusty-star rods lie
YOU'RE AT NE END.
<BLANKLINE>
>>> throw(rod) # will the correct rod get dropped?
OK
<BLANKLINE>
>>> look
YOU ARE AT THE NORTHEAST END OF AN IMMENSE ROOM, EVEN LARGER THAN THE
GIANT ROOM. IT APPEARS TO BE A REPOSITORY FOR THE "ADVENTURE"
PROGRAM. MASSIVE TORCHES FAR OVERHEAD BATHE THE ROOM WITH SMOKY
YELLOW LIGHT. SCATTERED ABOUT YOU CAN BE SEEN A PILE OF BOTTLES (ALL
OF THEM EMPTY), A NURSERY OF YOUNG BEANSTALKS MURMURING QUIETLY, A BED
OF OYSTERS, A BUNDLE OF BLACK RODS WITH RUSTY STARS ON THEIR ENDS, AND
A COLLECTION OF BRASS LANTERNS. OFF TO ONE SIDE A GREAT MANY DWARVES
ARE SLEEPING ON THE FLOOR, SNORING LOUDLY. A SIGN NEARBY READS: "DO
NOT DISTURB THE DWARVES!" AN IMMENSE MIRROR IS HANGING AGAINST ONE
WALL, AND STRETCHES TO THE OTHER END OF THE ROOM, WHERE VARIOUS OTHER
SUNDRY OBJECTS CAN BE GLIMPSED DIMLY IN THE DISTANCE.
<BLANKLINE>
A THREE FOOT BLACK ROD WITH A RUSTY MARK ON AN END LIES NEARBY.
<BLANKLINE>
>>> restart()
>>> find(eggs)
I DARESAY WHATEVER YOU WANT IS AROUND HERE SOMEWHERE.
<BLANKLINE>
>>> sw
YOU'RE AT SW END.
<BLANKLINE>
>>> get(rod)
OK
<BLANKLINE>
>>> blast
THERE IS A LOUD EXPLOSION, AND YOU ARE SUDDENLY SPLASHED ACROSS THE
WALLS OF THE ROOM.
<BLANKLINE>
<BLANKLINE>
YOU SCORED 113 OUT OF A POSSIBLE 350 USING 13 TURNS.
<BLANKLINE>
YOU HAVE ACHIEVED THE RATING: "EXPERIENCED ADVENTURER".
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 88 MORE POINTS
<BLANKLINE>
>>> restart()
>>> shatter(mirror)
YOU STRIKE THE MIRROR A RESOUNDING BLOW, WHEREUPON IT SHATTERS INTO A
MYRIAD TINY FRAGMENTS.
<BLANKLINE>
THE RESULTING RUCKUS HAS AWAKENED THE DWARVES. THERE ARE NOW SEVERAL
THREATENING LITTLE DWARVES IN THE ROOM WITH YOU! MOST OF THEM THROW
KNIVES AT YOU! ALL OF THEM GET YOU!
<BLANKLINE>
<BLANKLINE>
YOU SCORED 98 OUT OF A POSSIBLE 350 USING 10 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 33 MORE POINTS
<BLANKLINE>
>>> restart()
>>> wake(dwarves)
YOU PROD THE NEAREST DWARF, WHO WAKES UP GRUMPILY, TAKES ONE LOOK AT
YOU, CURSES, AND GRABS FOR HIS AXE.
<BLANKLINE>
THE RESULTING RUCKUS HAS AWAKENED THE DWARVES. THERE ARE NOW SEVERAL
THREATENING LITTLE DWARVES IN THE ROOM WITH YOU! MOST OF THEM THROW
KNIVES AT YOU! ALL OF THEM GET YOU!
<BLANKLINE>
<BLANKLINE>
YOU SCORED 98 OUT OF A POSSIBLE 350 USING 10 TURNS.
<BLANKLINE>
YOUR SCORE QUALIFIES YOU AS A NOVICE CLASS ADVENTURER.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 33 MORE POINTS
<BLANKLINE>
================================================
FILE: adventure/tests/walkthrough1.txt
================================================
>>> import adventure
>>> adventure.play(seed=1)
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
<BLANKLINE>
>>> yes
SOMEWHERE NEARBY IS COLOSSAL CAVE, WHERE OTHERS HAVE FOUND FORTUNES IN
TREASURE AND GOLD, THOUGH IT IS RUMORED THAT SOME WHO ENTER ARE NEVER
SEEN AGAIN. MAGIC IS SAID TO WORK IN THE CAVE. I WILL BE YOUR EYES
AND HANDS. DIRECT ME WITH COMMANDS OF 1 OR 2 WORDS. I SHOULD WARN
YOU THAT I LOOK AT ONLY THE FIRST FIVE LETTERS OF EACH WORD, SO YOU'LL
HAVE TO ENTER "NORTHEAST" AS "NE" TO DISTINGUISH IT FROM "NORTH".
(SHOULD YOU GET STUCK, TYPE "HELP" FOR SOME GENERAL HINTS. FOR INFOR-
MATION ON HOW TO END YOUR ADVENTURE, ETC., TYPE "INFO".)
- - -
THIS PROGRAM WAS ORIGINALLY DEVELOPED BY WILLIE CROWTHER. MOST OF THE
FEATURES OF THE CURRENT PROGRAM WERE ADDED BY DON WOODS (DON @ SU-AI).
CONTACT DON IF YOU HAVE ANY QUESTIONS, COMMENTS, ETC.
<BLANKLINE>
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.
<BLANKLINE>
>>> cave
I DON'T KNOW WHERE THE CAVE IS, BUT HEREABOUTS NO STREAM CAN RUN ON
THE SURFACE FOR LONG. I WOULD TRY THE STREAM.
<BLANKLINE>
YOU'RE AT END OF ROAD AGAIN.
<BLANKLINE>
>>> inven()
YOU'RE NOT CARRYING ANYTHING.
<BLANKLINE>
>>> west
YOU HAVE WALKED UP A HILL, STILL IN THE FOREST. THE ROAD SLOPES BACK
DOWN THE OTHER SIDE OF THE HILL. THERE IS A BUILDING IN THE DISTANCE.
<BLANKLINE>
>>> e
YOU'RE AT END OF ROAD AGAIN.
<BLANKLINE>
>>> e
YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS A SHINY BRASS LAMP NEARBY.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> downs
THE STREAM FLOWS OUT THROUGH A PAIR OF 1 FOOT DIAMETER SEWER PIPES.
IT WOULD BE ADVISABLE TO USE THE EXIT.
<BLANKLINE>
YOU'RE INSIDE BUILDING.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS A SHINY BRASS LAMP NEARBY.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> west
YOU'RE AT END OF ROAD AGAIN.
<BLANKLINE>
>>> s
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
ROCKY BED.
<BLANKLINE>
>>> s
AT YOUR FEET ALL THE WATER OF THE STREAM SPLASHES INTO A 2-INCH SLIT
IN THE ROCK. DOWNSTREAM THE STREAMBED IS BARE ROCK.
<BLANKLINE>
>>> s
YOU ARE IN A 20-FOOT DEPRESSION FLOORED WITH BARE DIRT. SET INTO THE
DIRT IS A STRONG STEEL GRATE MOUNTED IN CONCRETE. A DRY STREAMBED
LEADS INTO THE DEPRESSION.
<BLANKLINE>
THE GRATE IS LOCKED.
<BLANKLINE>
>>> d
YOU CAN'T GO THROUGH A LOCKED STEEL GRATE!
<BLANKLINE>
YOU'RE OUTSIDE GRATE.
<BLANKLINE>
THE GRATE IS LOCKED.
<BLANKLINE>
>>> get(grate)
YOU CAN'T BE SERIOUS!
<BLANKLINE>
>>> enter
YOU CAN'T GO THROUGH A LOCKED STEEL GRATE!
<BLANKLINE>
YOU'RE OUTSIDE GRATE.
<BLANKLINE>
THE GRATE IS LOCKED.
<BLANKLINE>
ARE YOU TRYING TO GET INTO THE CAVE?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> house
YOU'RE AT END OF ROAD AGAIN.
<BLANKLINE>
>>> enter
YOU'RE INSIDE BUILDING.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS A SHINY BRASS LAMP NEARBY.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> carry(keys)
OK
<BLANKLINE>
>>> inven
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
<BLANKLINE>
>>> leave
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.
<BLANKLINE>
>>> depre
YOU'RE OUTSIDE GRATE.
<BLANKLINE>
THE GRATE IS LOCKED.
<BLANKLINE>
>>> unloc(grate)
THE GRATE IS NOW UNLOCKED.
<BLANKLINE>
>>> d
YOU ARE IN A SMALL CHAMBER BENEATH A 3X3 STEEL GRATE TO THE SURFACE.
A LOW CRAWL OVER COBBLES LEADS INWARD TO THE WEST.
<BLANKLINE>
THE GRATE IS OPEN.
<BLANKLINE>
>>> s
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE BELOW THE GRATE.
<BLANKLINE>
THE GRATE IS OPEN.
<BLANKLINE>
>>> west
YOU ARE CRAWLING OVER COBBLES IN A LOW PASSAGE. THERE IS A DIM LIGHT
AT THE EAST END OF THE PASSAGE.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
>>> take(cage)
OK
<BLANKLINE>
>>> west
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> west
YOU FELL INTO A PIT AND BROKE EVERY BONE IN YOUR BODY!
<BLANKLINE>
OH DEAR, YOU SEEM TO HAVE GOTTEN YOURSELF KILLED. I MIGHT BE ABLE TO
HELP YOU OUT, BUT I'VE NEVER REALLY DONE THIS BEFORE. DO YOU WANT ME
TO TRY TO REINCARNATE YOU?
<BLANKLINE>
>>> save
PLEASE ANSWER THE QUESTION.
<BLANKLINE>
>>> yes
ALL RIGHT. BUT DON'T BLAME ME IF SOMETHING GOES WR......
--- POOF!! ---
YOU ARE ENGULFED IN A CLOUD OF ORANGE SMOKE. COUGHING AND GASPING,
YOU EMERGE FROM THE SMOKE AND FIND....
<BLANKLINE>
YOU'RE INSIDE BUILDING.
<BLANKLINE>
THERE IS A SHINY BRASS LAMP NEARBY.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> get(lamp)
OK
<BLANKLINE>
>>> leave
YOU'RE AT END OF ROAD AGAIN.
<BLANKLINE>
>>> depre
YOU'RE OUTSIDE GRATE.
<BLANKLINE>
THE GRATE IS OPEN.
<BLANKLINE>
>>> d
YOU'RE BELOW THE GRATE.
<BLANKLINE>
THE GRATE IS OPEN.
<BLANKLINE>
>>> west
YOU'RE IN COBBLE CRAWL.
<BLANKLINE>
>>> west
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> light(lamp)
YOUR LAMP IS NOW ON.
<BLANKLINE>
YOU ARE IN A DEBRIS ROOM FILLED WITH STUFF WASHED IN FROM THE SURFACE.
A LOW WIDE PASSAGE WITH COBBLES BECOMES PLUGGED WITH MUD AND DEBRIS
HERE, BUT AN AWKWARD CANYON LEADS UPWARD AND WEST. A NOTE ON THE WALL
SAYS "MAGIC WORD XYZZY".
<BLANKLINE>
A THREE FOOT BLACK ROD WITH A RUSTY STAR ON AN END LIES NEARBY.
<BLANKLINE>
>>> get(rod)
OK
<BLANKLINE>
>>> up
YOU ARE IN AN AWKWARD SLOPING EAST/WEST CANYON.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
>>> get(keys)
OK
<BLANKLINE>
>>> u
YOU ARE IN A SPLENDID CHAMBER THIRTY FEET HIGH. THE WALLS ARE FROZEN
RIVERS OF ORANGE STONE. AN AWKWARD CANYON AND A GOOD PASSAGE EXIT
FROM EAST AND WEST SIDES OF THE CHAMBER.
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> get(bird)
THE BIRD WAS UNAFRAID WHEN YOU ENTERED, BUT AS YOU APPROACH IT BECOMES
DISTURBED AND YOU CANNOT CATCH IT.
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
BLACK ROD
<BLANKLINE>
>>> drop(rod)
OK
<BLANKLINE>
>>> inven
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
<BLANKLINE>
>>> get(bird)
YOU CAN CATCH THE BIRD, BUT YOU CANNOT CARRY IT.
<BLANKLINE>
>>> e
YOU ARE IN AN AWKWARD SLOPING EAST/WEST CANYON.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
>>> get(cage)
OK
<BLANKLINE>
>>> west
YOU'RE IN BIRD CHAMBER.
<BLANKLINE>
A THREE FOOT BLACK ROD WITH A RUSTY STAR ON AN END LIES NEARBY.
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> get(bird)
OK
<BLANKLINE>
>>> get(rod)
OK
<BLANKLINE>
>>> look
SORRY, BUT I AM NOT ALLOWED TO GIVE MORE DETAIL. I WILL REPEAT THE
LONG DESCRIPTION OF YOUR LOCATION.
<BLANKLINE>
YOU ARE IN A SPLENDID CHAMBER THIRTY FEET HIGH. THE WALLS ARE FROZEN
RIVERS OF ORANGE STONE. AN AWKWARD CANYON AND A GOOD PASSAGE EXIT
FROM EAST AND WEST SIDES OF THE CHAMBER.
<BLANKLINE>
>>> west
AT YOUR FEET IS A SMALL PIT BREATHING TRACES OF WHITE MIST. AN EAST
PASSAGE ENDS HERE EXCEPT FOR A SMALL CRACK LEADING ON.
<BLANKLINE>
ROUGH STONE STEPS LEAD DOWN THE PIT.
<BLANKLINE>
>>> west
IF YOU PREFER, SIMPLY TYPE W RATHER THAN WEST.
<BLANKLINE>
THE CRACK IS FAR TOO SMALL FOR YOU TO FOLLOW.
<BLANKLINE>
YOU'RE AT TOP OF SMALL PIT.
<BLANKLINE>
ROUGH STONE STEPS LEAD DOWN THE PIT.
<BLANKLINE>
>>> look
SORRY, BUT I AM NOT ALLOWED TO GIVE MORE DETAIL. I WILL REPEAT THE
LONG DESCRIPTION OF YOUR LOCATION.
<BLANKLINE>
AT YOUR FEET IS A SMALL PIT BREATHING TRACES OF WHITE MIST. AN EAST
PASSAGE ENDS HERE EXCEPT FOR A SMALL CRACK LEADING ON.
<BLANKLINE>
ROUGH STONE STEPS LEAD DOWN THE PIT.
<BLANKLINE>
>>> d
YOU ARE AT ONE END OF A VAST HALL STRETCHING FORWARD OUT OF SIGHT TO
THE WEST. THERE ARE OPENINGS TO EITHER SIDE. NEARBY, A WIDE STONE
STAIRCASE LEADS DOWNWARD. THE HALL IS FILLED WITH WISPS OF WHITE MIST
SWAYING TO AND FRO ALMOST AS IF ALIVE. A COLD WIND BLOWS UP THE
STAIRCASE. THERE IS A PASSAGE AT THE TOP OF A DOME BEHIND YOU.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
>>> w
YOU ARE ON THE EAST BANK OF A FISSURE SLICING CLEAR ACROSS THE HALL.
THE MIST IS QUITE THICK HERE, AND THE FISSURE IS TOO WIDE TO JUMP.
<BLANKLINE>
>>> w
THERE IS NO WAY ACROSS THE FISSURE.
<BLANKLINE>
YOU'RE ON EAST BANK OF FISSURE.
<BLANKLINE>
>>> e
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
>>> n
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
A HUGE GREEN FIERCE SNAKE BARS THE WAY!
<BLANKLINE>
>>> s
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A HUGE GREEN FIERCE SNAKE BARS THE WAY!
<BLANKLINE>
>>> up
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
>>> down
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A HUGE GREEN FIERCE SNAKE BARS THE WAY!
<BLANKLINE>
>>> kill(snake)
ATTACKING THE SNAKE BOTH DOESN'T WORK AND IS VERY DANGEROUS.
<BLANKLINE>
>>> drop(cage)
OK
<BLANKLINE>
>>> look
SORRY, BUT I AM NOT ALLOWED TO GIVE MORE DETAIL. I WILL REPEAT THE
LONG DESCRIPTION OF YOUR LOCATION.
<BLANKLINE>
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
THERE IS A LITTLE BIRD IN THE CAGE.
<BLANKLINE>
A HUGE GREEN FIERCE SNAKE BARS THE WAY!
<BLANKLINE>
>>> get(bird)
OK
<BLANKLINE>
>>> look
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
A HUGE GREEN FIERCE SNAKE BARS THE WAY!
<BLANKLINE>
>>> inven
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
WICKER CAGE
BLACK ROD
LITTLE BIRD IN CAGE
<BLANKLINE>
>>> drop(bird)
THE LITTLE BIRD ATTACKS THE GREEN SNAKE, AND IN AN ASTOUNDING FLURRY
DRIVES THE SNAKE AWAY.
<BLANKLINE>
>>> look
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 42 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> s
A LITTLE DWARF JUST WALKED AROUND A CORNER, SAW YOU, THREW A LITTLE
AXE AT YOU WHICH MISSED, CURSED, AND RAN AWAY.
<BLANKLINE>
YOU ARE IN THE SOUTH SIDE CHAMBER.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
THERE IS PRECIOUS JEWELRY HERE!
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 44 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> get(jewelry)
OK
<BLANKLINE>
>>> n
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> w
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
YOU ARE IN THE WEST SIDE CHAMBER OF THE HALL OF THE MOUNTAIN KING.
A PASSAGE CONTINUES WEST AND UP HERE.
<BLANKLINE>
THERE ARE MANY COINS HERE!
<BLANKLINE>
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 46 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> get(coins)
OK
<BLANKLINE>
>>> w
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
YOU ARE AT A CROSSOVER OF A HIGH N/S PASSAGE AND A LOW E/W ONE.
<BLANKLINE>
>>> n
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
DEAD END
<BLANKLINE>
>>> s
A LITTLE DWARF WITH A BIG KNIFE BLOCKS YOUR WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
DEAD END
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU KILLED A LITTLE DWARF. THE BODY VANISHES IN A CLOUD OF GREASY
BLACK SMOKE.
<BLANKLINE>
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU KILLED A LITTLE DWARF.
<BLANKLINE>
DEAD END
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> s
YOU ARE AT A CROSSOVER OF A HIGH N/S PASSAGE AND A LOW E/W ONE.
<BLANKLINE>
>>> w
YOU ARE AT THE EAST END OF A VERY LONG HALL APPARENTLY WITHOUT SIDE
CHAMBERS. TO THE EAST A LOW WIDE CRAWL SLANTS UP. TO THE NORTH A
ROUND TWO FOOT HOLE SLANTS DOWN.
<BLANKLINE>
>>> w
YOU ARE AT THE WEST END OF A VERY LONG FEATURELESS HALL. THE HALL
JOINS UP WITH A NARROW NORTH/SOUTH PASSAGE.
<BLANKLINE>
>>> n
YOU ARE AT A CROSSOVER OF A HIGH N/S PASSAGE AND A LOW E/W ONE.
<BLANKLINE>
>>> n
DEAD END
<BLANKLINE>
>>> back
YOU ARE AT A CROSSOVER OF A HIGH N/S PASSAGE AND A LOW E/W ONE.
<BLANKLINE>
>>> w
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
>>> e
YOU ARE AT THE WEST END OF HALL OF MISTS. A LOW WIDE CRAWL CONTINUES
WEST AND ANOTHER GOES NORTH. TO THE SOUTH IS A LITTLE PASSAGE 6 FEET
OFF THE FLOOR.
<BLANKLINE>
>>> e
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE ARE DIAMONDS HERE!
<BLANKLINE>
>>> get(diamonds)
YOU CAN'T CARRY ANYTHING MORE. YOU'LL HAVE TO DROP SOMETHING FIRST.
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
WICKER CAGE
BLACK ROD
DWARF'S AXE
PRECIOUS JEWELRY
RARE COINS
<BLANKLINE>
>>> drop(cage)
OK
<BLANKLINE>
>>> get(diamonds)
OK
<BLANKLINE>
>>> n
YOU HAVE CRAWLED THROUGH A VERY LOW WIDE PASSAGE PARALLEL TO AND NORTH
OF THE HALL OF MISTS.
<BLANKLINE>
YOU'RE AT WEST END OF HALL OF MISTS.
<BLANKLINE>
>>> w
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
YOU ARE AT THE EAST END OF A VERY LONG HALL APPARENTLY WITHOUT SIDE
CHAMBERS. TO THE EAST A LOW WIDE CRAWL SLANTS UP. TO THE NORTH A
ROUND TWO FOOT HOLE SLANTS DOWN.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE ARE 2 THREATENING LITTLE DWARVES IN THE ROOM WITH YOU.
<BLANKLINE>
2 OF THEM THROW KNIVES AT YOU!
<BLANKLINE>
NONE OF THEM HIT YOU!
<BLANKLINE>
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU KILLED A LITTLE DWARF.
<BLANKLINE>
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
YOU ARE AT THE EAST END OF A VERY LONG HALL APPARENTLY WITHOUT SIDE
CHAMBERS. TO THE EAST A LOW WIDE CRAWL SLANTS UP. TO THE NORTH A
ROUND TWO FOOT HOLE SLANTS DOWN.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> throw(axe)
YOU ATTACK A LITTLE DWARF, BUT HE DODGES OUT OF THE WAY.
<BLANKLINE>
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT GETS YOU!
<BLANKLINE>
YOU CLUMSY OAF, YOU'VE DONE IT AGAIN! I DON'T KNOW HOW LONG I CAN
KEEP THIS UP. DO YOU WANT ME TO TRY REINCARNATING YOU AGAIN?
<BLANKLINE>
>>> get(axe)
PLEASE ANSWER THE QUESTION.
<BLANKLINE>
>>> yes
OKAY, NOW WHERE DID I PUT MY ORANGE SMOKE?.... >POOF!<
EVERYTHING DISAPPEARS IN A DENSE CLOUD OF ORANGE SMOKE.
<BLANKLINE>
YOU'RE INSIDE BUILDING.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> leave
YOU'RE AT END OF ROAD AGAIN.
<BLANKLINE>
THERE IS A SHINY BRASS LAMP NEARBY.
<BLANKLINE>
>>> get(lamp)
OK
<BLANKLINE>
>>> enter
YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> xyzzy
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> import io
>>> savefile = io.BytesIO()
>>> save(savefile)
GAME SAVED
<BLANKLINE>
>>> w
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> w
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> w
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> w
THE CRACK IS FAR TOO SMALL FOR YOU TO FOLLOW.
<BLANKLINE>
YOU FELL INTO A PIT AND BROKE EVERY BONE IN YOUR BODY!
<BLANKLINE>
NOW YOU'VE REALLY DONE IT! I'M OUT OF ORANGE SMOKE! YOU DON'T EXPECT
ME TO DO A DECENT REINCARNATION WITHOUT ANY ORANGE SMOKE, DO YOU?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
<BLANKLINE>
YOU SCORED 32 OUT OF A POSSIBLE 350 USING 132 TURNS.
<BLANKLINE>
YOU ARE OBVIOUSLY A RANK AMATEUR. BETTER LUCK NEXT TIME.
<BLANKLINE>
TO ACHIEVE THE NEXT HIGHER RATING, YOU NEED 69 MORE POINTS
<BLANKLINE>
>>> w
YOU HAVE GOTTEN YOURSELF KILLED.
<BLANKLINE>
>>> savefile.seek(0)
0
>>> adventure.resume(savefile)
GAME RESTORED
<BLANKLINE>
>>> on(lamp)
YOUR LAMP IS NOW ON.
<BLANKLINE>
YOU'RE IN DEBRIS ROOM.
<BLANKLINE>
>>> w
YOU ARE IN AN AWKWARD SLOPING EAST/WEST CANYON.
<BLANKLINE>
>>> w
YOU'RE IN BIRD CHAMBER.
<BLANKLINE>
>>> w
YOU'RE AT TOP OF SMALL PIT.
<BLANKLINE>
ROUGH STONE STEPS LEAD DOWN THE PIT.
<BLANKLINE>
>>> d
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
>>> d
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> w
YOU ARE IN THE WEST SIDE CHAMBER OF THE HALL OF THE MOUNTAIN KING.
A PASSAGE CONTINUES WEST AND UP HERE.
<BLANKLINE>
>>> w
YOU ARE AT A CROSSOVER OF A HIGH N/S PASSAGE AND A LOW E/W ONE.
<BLANKLINE>
>>> w
YOU'RE AT EAST END OF LONG HALL.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
A THREE FOOT BLACK ROD WITH A RUSTY STAR ON AN END LIES NEARBY.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
THERE ARE DIAMONDS HERE!
<BLANKLINE>
THERE IS PRECIOUS JEWELRY HERE!
<BLANKLINE>
THERE ARE MANY COINS HERE!
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> get(keys)
OK
<BLANKLINE>
>>> get(rod)
OK
<BLANKLINE>
>>> get(diamonds)
OK
<BLANKLINE>
>>> get(jewel)
OK
<BLANKLINE>
>>> get(coins)
OK
<BLANKLINE>
>>> e
YOU'RE AT WEST END OF HALL OF MISTS.
<BLANKLINE>
>>> e
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
>>> jump
I DON'T KNOW HOW TO APPLY THAT WORD HERE.
<BLANKLINE>
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
>>> swing(rod)
A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
<BLANKLINE>
>>> look
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
<BLANKLINE>
>>> jump
I RESPECTFULLY SUGGEST YOU GO ACROSS THE BRIDGE INSTEAD OF JUMPING.
<BLANKLINE>
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
<BLANKLINE>
>>> over
YOU'RE ON EAST BANK OF FISSURE.
<BLANKLINE>
A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
<BLANKLINE>
>>> e
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
>>> s
THIS IS A LOW ROOM WITH A CRUDE NOTE ON THE WALL. THE NOTE SAYS,
"YOU WON'T GET IT UP THE STEPS".
<BLANKLINE>
THERE IS A LARGE SPARKLING NUGGET OF GOLD HERE!
<BLANKLINE>
>>> get(gold)
YOU CAN'T CARRY ANYTHING MORE. YOU'LL HAVE TO DROP SOMETHING FIRST.
<BLANKLINE>
>>> drop(rod)
OK
<BLANKLINE>
>>> get(gold)
OK
<BLANKLINE>
>>> n
YOU ARE AT ONE END OF A VAST HALL STRETCHING FORWARD OUT OF SIGHT TO
THE WEST. THERE ARE OPENINGS TO EITHER SIDE. NEARBY, A WIDE STONE
STAIRCASE LEADS DOWNWARD. THE HALL IS FILLED WITH WISPS OF WHITE MIST
SWAYING TO AND FRO ALMOST AS IF ALIVE. A COLD WIND BLOWS UP THE
STAIRCASE. THERE IS A PASSAGE AT THE TOP OF A DOME BEHIND YOU.
<BLANKLINE>
>>> u
THE DOME IS UNCLIMBABLE.
<BLANKLINE>
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
>>> drop(gold)
OK
<BLANKLINE>
>>> u
YOU'RE AT TOP OF SMALL PIT.
<BLANKLINE>
ROUGH STONE STEPS LEAD DOWN THE PIT.
<BLANKLINE>
>>> e
YOU'RE IN BIRD CHAMBER.
<BLANKLINE>
>>> e
YOU ARE IN AN AWKWARD SLOPING EAST/WEST CANYON.
<BLANKLINE>
>>> e
YOU'RE IN DEBRIS ROOM.
<BLANKLINE>
>>> xyzzy
YOU'RE INSIDE BUILDING.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 40 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
DWARF'S AXE
SEVERAL DIAMONDS
PRECIOUS JEWELRY
RARE COINS
<BLANKLINE>
>>> drop(diamonds)
OK
<BLANKLINE>
>>> drop(jewelry)
OK
<BLANKLINE>
>>> drop(coins)
OK
<BLANKLINE>
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 70 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> no
OK
<BLANKLINE>
>>> xyzzy
YOU'RE IN DEBRIS ROOM.
<BLANKLINE>
>>> w
YOU ARE IN AN AWKWARD SLOPING EAST/WEST CANYON.
<BLANKLINE>
>>> w
YOU'RE IN BIRD CHAMBER.
<BLANKLINE>
>>> w
YOU'RE AT TOP OF SMALL PIT.
<BLANKLINE>
ROUGH STONE STEPS LEAD DOWN THE PIT.
<BLANKLINE>
>>> d
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
THERE IS A LARGE SPARKLING NUGGET OF GOLD HERE!
<BLANKLINE>
>>> get(gold)
OK
<BLANKLINE>
>>> n
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> n
YOU ARE IN A LOW N/S PASSAGE AT A HOLE IN THE FLOOR. THE HOLE GOES
DOWN TO AN E/W PASSAGE.
<BLANKLINE>
THERE ARE BARS OF SILVER HERE!
<BLANKLINE>
>>> get(silver)
OK
<BLANKLINE>
>>> n
YOU ARE IN A LARGE ROOM, WITH A PASSAGE TO THE SOUTH, A PASSAGE TO THE
WEST, AND A WALL OF BROKEN ROCK TO THE EAST. THERE IS A LARGE "Y2" ON
A ROCK IN THE ROOM'S CENTER.
<BLANKLINE>
>>> w
YOU'RE AT A LOW WINDOW OVERLOOKING A HUGE PIT, WHICH EXTENDS UP OUT OF
SIGHT. A FLOOR IS INDISTINCTLY VISIBLE OVER 50 FEET BELOW. TRACES OF
WHITE MIST COVER THE FLOOR OF THE PIT, BECOMING THICKER TO THE RIGHT.
MARKS IN THE DUST AROUND THE WINDOW WOULD SEEM TO INDICATE THAT
SOMEONE HAS BEEN HERE RECENTLY. DIRECTLY ACROSS THE PIT FROM YOU AND
25 FEET AWAY THERE IS A SIMILAR WINDOW LOOKING INTO A LIGHTED ROOM. A
SHADOWY FIGURE CAN BE SEEN THERE PEERING BACK AT YOU.
<BLANKLINE>
THE SHADOWY FIGURE SEEMS TO BE TRYING TO ATTRACT YOUR ATTENTION.
<BLANKLINE>
>>> wave
WAVE WHAT?
<BLANKLINE>
>>> e
YOU'RE AT "Y2".
<BLANKLINE>
>>> e
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> e
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU ARE IN A JUMBLE OF ROCK, WITH CRACKS EVERYWHERE.
<BLANKLINE>
>>> d
YOU'RE AT "Y2".
<BLANKLINE>
>>> s
YOU ARE IN A LOW N/S PASSAGE AT A HOLE IN THE FLOOR. THE HOLE GOES
DOWN TO AN E/W PASSAGE.
<BLANKLINE>
>>> s
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> nw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> ne
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> se
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> sw
YOU ARE IN A SECRET CANYON WHICH HERE RUNS E/W. IT CROSSES OVER A
VERY TIGHT CANYON 15 FEET BELOW. IF YOU GO DOWN YOU MAY NOT BE ABLE
TO GET BACK UP.
<BLANKLINE>
>>> w
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
A HUGE GREEN FIERCE DRAGON BARS THE WAY!
<BLANKLINE>
THE DRAGON IS SPRAWLED OUT ON A PERSIAN RUG!!
<BLANKLINE>
>>> w
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
A HUGE GREEN FIERCE DRAGON BARS THE WAY!
<BLANKLINE>
THE DRAGON IS SPRAWLED OUT ON A PERSIAN RUG!!
<BLANKLINE>
>>> e
YOU'RE IN SECRET E/W CANYON ABOVE TIGHT CANYON.
<BLANKLINE>
>>> e
OUT FROM THE SHADOWS BEHIND YOU POUNCES A BEARDED PIRATE! "HAR, HAR,"
HE CHORTLES, "I'LL JUST TAKE ALL THIS BOOTY AND HIDE IT AWAY WITH ME
CHEST DEEP IN THE MAZE!" HE SNATCHES YOUR TREASURE AND VANISHES INTO
THE GLOOM.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
DWARF'S AXE
<BLANKLINE>
>>> get(bird)
YOU CAN CATCH THE BIRD, BUT YOU CANNOT CARRY IT.
<BLANKLINE>
>>> u
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
>>> w
YOU'RE ON EAST BANK OF FISSURE.
<BLANKLINE>
A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
<BLANKLINE>
>>> w
YOU ARE ON THE WEST SIDE OF THE FISSURE IN THE HALL OF MISTS.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
<BLANKLINE>
>>> get(cage)
OK
<BLANKLINE>
>>> e
YOU'RE ON EAST BANK OF FISSURE.
<BLANKLINE>
A CRYSTAL BRIDGE NOW SPANS THE FISSURE.
<BLANKLINE>
>>> e
YOU'RE IN HALL OF MISTS.
<BLANKLINE>
ROUGH STONE STEPS LEAD UP THE DOME.
<BLANKLINE>
>>> d
YOU'RE IN HALL OF MT KING
<BLANKLINE>
A CHEERFUL LITTLE BIRD IS SITTING HERE SINGING.
<BLANKLINE>
>>> get(bird)
OK
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
YOU ARE IN THE HALL OF THE MOUNTAIN KING, WITH PASSAGES OFF IN ALL
DIRECTIONS.
<BLANKLINE>
>>> sw
YOU'RE IN SECRET E/W CANYON ABOVE TIGHT CANYON.
<BLANKLINE>
>>> w
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
A HUGE GREEN FIERCE DRAGON BARS THE WAY!
<BLANKLINE>
THE DRAGON IS SPRAWLED OUT ON A PERSIAN RUG!!
<BLANKLINE>
>>> drop(bird)
THE LITTLE BIRD ATTACKS THE GREEN DRAGON, AND IN AN ASTOUNDING FLURRY
GETS BURNT TO A CINDER. THE ASHES BLOW AWAY.
<BLANKLINE>
>>> n
THE DRAGON LOOKS RATHER NASTY. YOU'D BEST NOT TRY TO GET BY.
<BLANKLINE>
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
A HUGE GREEN FIERCE DRAGON BARS THE WAY!
<BLANKLINE>
THE DRAGON IS SPRAWLED OUT ON A PERSIAN RUG!!
<BLANKLINE>
>>> kill(dragon)
WITH WHAT? YOUR BARE HANDS?
<BLANKLINE>
>>> throw(axe)
THE AXE BOUNCES HARMLESSLY OFF THE DRAGON'S THICK SCALES.
<BLANKLINE>
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
A HUGE GREEN FIERCE DRAGON BARS THE WAY!
<BLANKLINE>
THE DRAGON IS SPRAWLED OUT ON A PERSIAN RUG!!
<BLANKLINE>
>>> yes
I DON'T KNOW THAT WORD.
<BLANKLINE>
>>> kill(dragon)
WITH WHAT? YOUR BARE HANDS?
<BLANKLINE>
>>> yes
CONGRATULATIONS! YOU HAVE JUST VANQUISHED A DRAGON WITH YOUR BARE
HANDS! (UNBELIEVABLE, ISN'T IT?)
<BLANKLINE>
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
THE BODY OF A HUGE GREEN DEAD DRAGON IS LYING OFF TO ONE SIDE.
<BLANKLINE>
THERE IS A PERSIAN RUG SPREAD OUT ON THE FLOOR!
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> get(dragon)
YOU CAN'T BE SERIOUS!
<BLANKLINE>
>>> get(rug)
OK
<BLANKLINE>
>>> n
YOU ARE IN A SECRET N/S CANYON ABOVE A LARGE ROOM.
<BLANKLINE>
>>> n
YOU ARE IN A NORTH/SOUTH CANYON ABOUT 25 FEET ACROSS. THE FLOOR IS
COVERED BY WHITE MIST SEEPING IN FROM THE NORTH. THE WALLS EXTEND
UPWARD FOR WELL OVER 100 FEET. SUSPENDED FROM SOME UNSEEN POINT FAR
ABOVE YOU, AN ENORMOUS TWO-SIDED MIRROR IS HANGING PARALLEL TO AND
MIDWAY BETWEEN THE CANYON WALLS. (THE MIRROR IS OBVIOUSLY PROVIDED
FOR THE USE OF THE DWARVES, WHO AS YOU KNOW, ARE EXTREMELY VAIN.) A
SMALL WINDOW CAN BE SEEN IN EITHER WALL, SOME FIFTY FEET UP.
<BLANKLINE>
>>> n
YOU ARE AT THE EDGE OF A LARGE UNDERGROUND RESERVOIR. AN OPAQUE CLOUD
OF WHITE MIST FILLS THE ROOM AND RISES RAPIDLY UPWARD. THE LAKE IS
FED BY A STREAM, WHICH TUMBLES OUT OF A HOLE IN THE WALL ABOUT 10 FEET
OVERHEAD AND SPLASHES NOISILY INTO THE WATER SOMEWHERE WITHIN THE
MIST. THE ONLY PASSAGE GOES BACK TOWARD THE SOUTH.
<BLANKLINE>
>>> s
YOU'RE IN MIRROR CANYON.
<BLANKLINE>
>>> s
YOU ARE IN A SECRET N/S CANYON ABOVE A LARGE ROOM.
<BLANKLINE>
>>> s
YOU ARE IN A SECRET CANYON WHICH EXITS TO THE NORTH AND EAST.
<BLANKLINE>
THE BODY OF A HUGE GREEN DEAD DRAGON IS LYING OFF TO ONE SIDE.
<BLANKLINE>
>>> e
YOU'RE IN SECRET E/W CANYON ABOVE TIGHT CANYON.
<BLANKLINE>
>>> e
YOU'RE IN HALL OF MT KING
<BLANKLINE>
>>> n
YOU ARE IN A LOW N/S PASSAGE AT A HOLE IN THE FLOOR. THE HOLE GOES
DOWN TO AN E/W PASSAGE.
<BLANKLINE>
>>> n
YOU'RE AT "Y2".
<BLANKLINE>
>>> w
YOU'RE AT WINDOW ON PIT.
<BLANKLINE>
THE SHADOWY FIGURE SEEMS TO BE TRYING TO ATTRACT YOUR ATTENTION.
<BLANKLINE>
>>> e
YOU'RE AT "Y2".
<BLANKLINE>
A HOLLOW VOICE SAYS "PLUGH".
<BLANKLINE>
>>> plugh
YOU'RE INSIDE BUILDING.
<BLANKLINE>
THERE IS FOOD HERE.
<BLANKLINE>
THERE IS A BOTTLE OF WATER HERE.
<BLANKLINE>
THERE ARE DIAMONDS HERE!
<BLANKLINE>
THERE IS PRECIOUS JEWELRY HERE!
<BLANKLINE>
THERE ARE MANY COINS HERE!
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
WICKER CAGE
DWARF'S AXE
PERSIAN RUG
<BLANKLINE>
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 74 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> n
OK
<BLANKLINE>
>>> drop(persian)
OK
<BLANKLINE>
>>> score
IF YOU WERE TO QUIT NOW, YOU WOULD SCORE 88 OUT OF A POSSIBLE 350.
<BLANKLINE>
DO YOU INDEED WISH TO QUIT NOW?
<BLANKLINE>
>>> n
OK
<BLANKLINE>
>>> plugh
YOU ARE IN A LARGE ROOM, WITH A PASSAGE TO THE SOUTH, A PASSAGE TO THE
WEST, AND A WALL OF BROKEN ROCK TO THE EAST. THERE IS A LARGE "Y2" ON
A ROCK IN THE ROOM'S CENTER.
<BLANKLINE>
>>> s
YOU ARE IN A LOW N/S PASSAGE AT A HOLE IN THE FLOOR. THE HOLE GOES
DOWN TO AN E/W PASSAGE.
<BLANKLINE>
>>> d
YOU ARE IN A DIRTY BROKEN PASSAGE. TO THE EAST IS A CRAWL. TO THE
WEST IS A LARGE PASSAGE. ABOVE YOU IS A HOLE TO ANOTHER PASSAGE.
<BLANKLINE>
>>> e
YOU ARE ON THE BRINK OF A SMALL CLEAN CLIMBABLE PIT. A CRAWL LEADS
WEST.
<BLANKLINE>
>>> d
YOU ARE IN THE BOTTOM OF A SMALL PIT WITH A LITTLE STREAM, WHICH
ENTERS AND EXITS THROUGH TINY SLITS.
<BLANKLINE>
>>> u
YOU ARE ON THE BRINK OF A SMALL CLEAN CLIMBABLE PIT. A CRAWL LEADS
WEST.
<BLANKLINE>
>>> w
YOU'RE IN DIRTY PASSAGE.
<BLANKLINE>
>>> w
YOU ARE IN A LARGE ROOM FULL OF DUSTY ROCKS. THERE IS A BIG HOLE IN
THE FLOOR. THERE ARE CRACKS EVERYWHERE, AND A PASSAGE LEADING EAST.
<BLANKLINE>
>>> d
YOU ARE AT A COMPLEX JUNCTION. A LOW HANDS AND KNEES PASSAGE FROM THE
NORTH JOINS A HIGHER CRAWL FROM THE EAST TO MAKE A WALKING PASSAGE
GOING WEST. THERE IS ALSO A LARGE ROOM ABOVE. THE AIR IS DAMP HERE.
<BLANKLINE>
>>> n
YOU'RE IN A LARGE ROOM CARVED OUT OF SEDIMENTARY ROCK. THE FLOOR AND
WALLS ARE LITTERED WITH BITS OF SHELLS IMBEDDED IN THE STONE. A
SHALLOW PASSAGE PROCEEDS DOWNWARD, AND A SOMEWHAT STEEPER ONE LEADS
UP. A LOW HANDS AND KNEES PASSAGE ENTERS FROM THE SOUTH.
<BLANKLINE>
THERE IS AN ENORMOUS CLAM HERE WITH ITS SHELL TIGHTLY CLOSED.
<BLANKLINE>
>>> u
YOU ARE IN AN ARCHED HALL. A CORAL PASSAGE ONCE CONTINUED UP AND EAST
FROM HERE, BUT IS NOW BLOCKED BY DEBRIS. THE AIR SMELLS OF SEA WATER.
<BLANKLINE>
>>> d
YOU'RE IN SHELL ROOM.
<BLANKLINE>
THERE IS AN ENORMOUS CLAM HERE WITH ITS SHELL TIGHTLY CLOSED.
<BLANKLINE>
>>> d
YOU ARE IN A LONG SLOPING CORRIDOR WITH RAGGED SHARP WALLS.
<BLANKLINE>
>>> d
YOU ARE IN A CUL-DE-SAC ABOUT EIGHT FEET ACROSS.
<BLANKLINE>
>>> u
YOU ARE IN A LONG SLOPING CORRIDOR WITH RAGGED SHARP WALLS.
<BLANKLINE>
>>> u
YOU'RE IN SHELL ROOM.
<BLANKLINE>
THERE IS AN ENORMOUS CLAM HERE WITH ITS SHELL TIGHTLY CLOSED.
<BLANKLINE>
>>> get(clam)
OK
<BLANKLINE>
>>> s
YOU CAN'T FIT THIS FIVE-FOOT CLAM THROUGH THAT LITTLE PASSAGE!
<BLANKLINE>
YOU'RE IN SHELL ROOM.
<BLANKLINE>
>>> drop(clam)
OK
<BLANKLINE>
>>> unlock(clam)
YOU DON'T HAVE ANYTHING STRONG ENOUGH TO OPEN THE CLAM.
<BLANKLINE>
>>> s
YOU'RE AT COMPLEX JUNCTION.
<BLANKLINE>
>>> e
YOU ARE IN AN ANTEROOM LEADING TO A LARGE PASSAGE TO THE EAST. SMALL
PASSAGES GO WEST AND UP. THE REMNANTS OF RECENT DIGGING ARE EVIDENT.
A SIGN IN MIDAIR HERE SAYS "CAVE UNDER CONSTRUCTION BEYOND THIS POINT.
PROCEED AT OWN RISK. [WITT CONSTRUCTION COMPANY]"
<BLANKLINE>
THERE ARE A FEW RECENT ISSUES OF "SPELUNKER TODAY" MAGAZINE HERE.
<BLANKLINE>
>>> e
YOU ARE AT WITT'S END. PASSAGES LEAD OFF IN *ALL* DIRECTIONS.
<BLANKLINE>
>>> w
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND FOUND YOUR WAY
BLOCKED BY A RECENT CAVE-IN. YOU ARE NOW BACK IN THE MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> s
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> se
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU ARE AT WITT'S END. PASSAGES LEAD OFF IN *ALL* DIRECTIONS.
<BLANKLINE>
>>> nw
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> u
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> d
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> s
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU ARE AT WITT'S END. PASSAGES LEAD OFF IN *ALL* DIRECTIONS.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> se
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> nw
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> u
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> d
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU ARE AT WITT'S END. PASSAGES LEAD OFF IN *ALL* DIRECTIONS.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> s
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> se
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
DO YOU NEED HELP GETTING OUT OF HERE?
<BLANKLINE>
>>> yes
DON'T GO WEST.
<BLANKLINE>
>>> nw
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU ARE AT WITT'S END. PASSAGES LEAD OFF IN *ALL* DIRECTIONS.
<BLANKLINE>
>>> u
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> d
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU'RE AT WITT'S END.
<BLANKLINE>
>>> s
YOU'RE IN ANTEROOM.
<BLANKLINE>
THERE ARE A FEW RECENT ISSUES OF "SPELUNKER TODAY" MAGAZINE HERE.
<BLANKLINE>
>>> w
YOU ARE IN BEDQUILT, A LONG EAST/WEST PASSAGE WITH HOLES EVERYWHERE.
TO EXPLORE AT RANDOM SELECT NORTH, SOUTH, UP, OR DOWN.
<BLANKLINE>
>>> w
YOU ARE IN A ROOM WHOSE WALLS RESEMBLE SWISS CHEESE. OBVIOUS PASSAGES
GO WEST, EAST, NE, AND NW. PART OF THE ROOM IS OCCUPIED BY A LARGE
BEDROCK BLOCK.
<BLANKLINE>
>>> w
YOU ARE AT THE EAST END OF THE TWOPIT ROOM. THE FLOOR HERE IS
LITTERED WITH THIN ROCK SLABS, WHICH MAKE IT EASY TO DESCEND THE PITS.
THERE IS A PATH HERE BYPASSING THE PITS TO CONNECT PASSAGES FROM EAST
AND WEST. THERE ARE HOLES ALL OVER, BUT THE ONLY BIG ONE IS ON THE
WALL DIRECTLY OVER THE WEST PIT WHERE YOU CAN'T GET TO IT.
<BLANKLINE>
>>> d
YOU ARE AT THE BOTTOM OF THE EASTERN PIT IN THE TWOPIT ROOM. THERE IS
A SMALL POOL OF OIL IN ONE CORNER OF THE PIT.
<BLANKLINE>
>>> u
YOU'RE AT EAST END OF TWOPIT ROOM.
<BLANKLINE>
>>> w
THERE IS A THREATENING LITTLE DWARF IN THE ROOM WITH YOU!
<BLANKLINE>
ONE SHARP NASTY KNIFE IS THROWN AT YOU!
<BLANKLINE>
IT MISSES!
<BLANKLINE>
YOU ARE AT THE WEST END OF THE TWOPIT ROOM. THERE IS A LARGE HOLE IN
THE WALL ABOVE THE PIT AT THIS END OF THE ROOM.
<BLANKLINE>
>>> throw(axe)
YOU KILLED A LITTLE DWARF.
<BLANKLINE>
YOU'RE AT WEST END OF TWOPIT ROOM.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> down
YOU ARE AT THE BOTTOM OF THE WESTERN PIT IN THE TWOPIT ROOM. THERE IS
A LARGE HOLE IN THE WALL ABOUT 25 FEET ABOVE YOU.
<BLANKLINE>
THERE IS A TINY LITTLE PLANT IN THE PIT, MURMURING "WATER, WATER, ..."
<BLANKLINE>
>>> u
YOU'RE AT WEST END OF TWOPIT ROOM.
<BLANKLINE>
>>> w
YOU ARE IN A LARGE LOW CIRCULAR CHAMBER WHOSE FLOOR IS AN IMMENSE SLAB
FALLEN FROM THE CEILING (SLAB ROOM). EAST AND WEST THERE ONCE WERE
LARGE PASSAGES, BUT THEY ARE NOW FILLED WITH BOULDERS. LOW SMALL
PASSAGES GO NORTH AND SOUTH, AND THE SOUTH ONE QUICKLY BENDS WEST
AROUND THE BOULDERS.
<BLANKLINE>
>>> n
YOU ARE IN BEDQUILT, A LONG EAST/WEST PASSAGE WITH HOLES EVERYWHERE.
TO EXPLORE AT RANDOM SELECT NORTH, SOUTH, UP, OR DOWN.
<BLANKLINE>
>>> n
YOU HAVE CRAWLED AROUND IN SOME LITTLE HOLES AND WOUND UP BACK IN THE
MAIN PASSAGE.
<BLANKLINE>
YOU ARE IN BEDQUILT, A LONG EAST/WEST PASSAGE WITH HOLES EVERYWHERE.
TO EXPLORE AT RANDOM SELECT NORTH, SOUTH, UP, OR DOWN.
<BLANKLINE>
>>> n
YOU ARE IN A LARGE LOW ROOM. CRAWLS LEAD NORTH, SE, AND SW.
<BLANKLINE>
>>> n
DEAD END CRAWL.
<BLANKLINE>
>>> s
YOU ARE IN A LARGE LOW ROOM. CRAWLS LEAD NORTH, SE, AND SW.
<BLANKLINE>
>>> sw
YOU ARE IN A LONG WINDING CORRIDOR SLOPING OUT OF SIGHT IN BOTH
DIRECTIONS.
<BLANKLINE>
>>> u
YOU ARE ON ONE SIDE OF A LARGE, DEEP CHASM. A HEAVY WHITE MIST RISING
UP FROM BELOW OBSCURES ALL VIEW OF THE FAR SIDE. A SW PATH LEADS AWAY
FROM THE CHASM INTO A WINDING CORRIDOR.
<BLANKLINE>
A RICKETY WOODEN BRIDGE EXTENDS ACROSS THE CHASM, VANISHING INTO THE
MIST. A SIGN POSTED ON THE BRIDGE READS, "STOP! PAY TROLL!"
<BLANKLINE>
A BURLY TROLL STANDS BY THE BRIDGE AND INSISTS YOU THROW HIM A
TREASURE BEFORE YOU MAY CROSS.
<BLANKLINE>
>>> sw
YOU'RE IN SLOPING CORRIDOR.
<BLANKLINE>
>>> d
YOU ARE IN A LARGE LOW ROOM. CRAWLS LEAD NORTH, SE, AND SW.
<BLANKLINE>
>>> se
THIS IS THE ORIENTAL ROOM. ANCIENT ORIENTAL CAVE DRAWINGS COVER THE
WALLS. A GENTLY SLOPING PASSAGE LEADS UPWARD TO THE NORTH, ANOTHER
PASSAGE LEADS SE, AND A HANDS AND KNEES CRAWL LEADS WEST.
<BLANKLINE>
THERE IS A DELICATE, PRECIOUS, MING VASE HERE!
<BLANKLINE>
>>> get(vase)
OK
<BLANKLINE>
>>> n
YOU ARE FOLLOWING A WIDE PATH AROUND THE OUTER EDGE OF A LARGE CAVERN.
FAR BELOW, THROUGH A HEAVY WHITE MIST, STRANGE SPLASHING NOISES CAN BE
HEARD. THE MIST RISES UP THROUGH A FISSURE IN THE CEILING. THE PATH
EXITS TO THE SOUTH AND WEST.
<BLANKLINE>
>>> w
YOU ARE IN AN ALCOVE. A SMALL NW PATH SEEMS TO WIDEN AFTER A SHORT
DISTANCE. AN EXTREMELY TIGHT TUNNEL LEADS EAST. IT LOOKS LIKE A VERY
TIGHT SQUEEZE. AN EERIE LIGHT CAN BE SEEN AT THE OTHER END.
<BLANKLINE>
>>> e
SOMETHING YOU'RE CARRYING WON'T FIT THROUGH THE TUNNEL WITH YOU.
YOU'D BEST TAKE INVENTORY AND DROP SOMETHING.
<BLANKLINE>
OUT FROM THE SHADOWS BEHIND YOU POUNCES A BEARDED PIRATE! "HAR, HAR,"
HE CHORTLES, "I'LL JUST TAKE ALL THIS BOOTY AND HIDE IT AWAY WITH ME
CHEST DEEP IN THE MAZE!" HE SNATCHES YOUR TREASURE AND VANISHES INTO
THE GLOOM.
<BLANKLINE>
YOU'RE IN ALCOVE.
<BLANKLINE>
>>> inventory
YOU ARE CURRENTLY HOLDING THE FOLLOWING:
<BLANKLINE>
SET OF KEYS
BRASS LANTERN
WICKER CAGE
DWARF'S AXE
<BLANKLINE>
>>> drop(keys)
OK
<BLANKLINE>
>>> drop(lantern)
OK
<BLANKLINE>
>>> drop(cage)
OK
<BLANKLINE>
>>> drop(axe)
OK
<BLANKLINE>
>>> e
YOU'RE IN A SMALL CHAMBER LIT BY AN EERIE GREEN LIGHT. AN EXTREMELY
NARROW TUNNEL EXITS TO THE WEST. A DARK CORRIDOR LEADS NE.
<BLANKLINE>
THERE IS AN EMERALD HERE THE SIZE OF A PLOVER'S EGG!
<BLANKLINE>
>>> get(emerald)
OK
<BLANKLINE>
>>> ne
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> sw
THERE IS NO WAY TO GO THAT DIRECTION.
<BLANKLINE>
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> s
YOU'RE IN PLOVER ROOM.
<BLANKLINE>
>>> plover
IT IS NOW PITCH DARK. IF YOU PROCEED YOU WILL LIKELY FALL INTO A PIT.
<BLANKLINE>
>>> drop(emerald)
I SEE NO EMERALD HERE.
<BLANKLINE>
>>> plover
YOU'RE IN PLOVER ROOM.
<BLANKLINE>
THERE IS AN EMERALD HERE THE SIZE OF A PLOVER'S EGG!
<BLANKLINE>
>>> get(emerald)
OK
<BLANKLINE>
>>> w
YOU'RE IN ALCOVE.
<BLANKLINE>
THERE ARE SOME KEYS ON THE GROUND HERE.
<BLANKLINE>
THERE IS A LAMP SHINING NEARBY.
<BLANKLINE>
THERE IS A SMALL WICKER CAGE DISCARDED NEARBY.
<BLANKLINE>
THERE IS A LITTLE AXE HERE.
<BLANKLINE>
>>> get(keys)
OK
<BLANKLINE>
>>> get(lamp)
OK
<BLANKLINE>
>>> get(axe)
OK
<BLANKLINE>
>>> nw
YOU'RE IN MISTY CAVERN.
<BLANKLINE>
>>> s
YOU'RE IN ORIENTAL ROOM.
<BLANKLINE>
>>> se
YOU'RE IN SWISS CHEESE ROOM.
<BLANKLINE>
>>> e
YOU ARE IN THE SOFT ROOM. THE WALLS ARE COVERED WITH HEAVY CURTAINS,
THE FLOOR WITH A THICK PILE CARPET. MOSS COVERS THE CEILING.
<BLANKLINE>
A SMALL VELVET PILLOW LIES ON THE FLOOR.
<BLANKLINE>
>>> get(pillow)
OK
<BLANKLINE>
>>> w
YOU'RE IN SWISS CHEESE ROOM.
<BLANKLINE>
>>> ne
YOU ARE IN BEDQUILT, A LONG EAST/WEST PASSAGE WITH HOLES EVERYWHERE.
TO EXPLORE AT RANDOM SELEC
gitextract_kuy29xws/ ├── .gitignore ├── LICENSE.ASF-2 ├── README.md ├── adventure/ │ ├── MANIFEST.in │ ├── README.txt │ ├── TODO.txt │ ├── __init__.py │ ├── __main__.py │ ├── data.py │ ├── game.py │ ├── model.py │ ├── prompt.py │ └── tests/ │ ├── __init__.py │ ├── syntax.txt │ ├── test_commands.py │ ├── test_data.py │ ├── test_walks.py │ ├── vignettes.txt │ ├── walkthrough1.txt │ ├── walkthrough2.txt │ ├── walkthrough3.txt │ └── walkthrough4.txt └── setup.py
SYMBOL INDEX (161 symbols across 9 files)
FILE: adventure/__init__.py
function load_advent_dat (line 12) | def load_advent_dat(data):
function play (line 20) | def play(seed=None):
function resume (line 38) | def resume(savefile, quiet=False):
FILE: adventure/__main__.py
function baudout (line 18) | def baudout(s):
function loop (line 25) | def loop(args):
FILE: adventure/data.py
class Data (line 30) | class Data(object):
method __init__ (line 31) | def __init__(self):
method referent (line 40) | def referent(self, word):
function make_object (line 46) | def make_object(dictionary, klass, n):
function expand_tabs (line 52) | def expand_tabs(segments):
function accumulate_message (line 60) | def accumulate_message(dictionary, n, line):
function section1 (line 65) | def section1(data, n, *etc):
function section2 (line 77) | def section2(data, n, line):
function section3 (line 86) | def section3(data, x, y, *verbs):
function section4 (line 176) | def section4(data, n, text, *etc):
function section5 (line 210) | def section5(data, n, *etc):
function section6 (line 236) | def section6(data, n, *etc):
function section7 (line 247) | def section7(data, n, room_n, fixed=None):
function section8 (line 269) | def section8(data, word_n, message_n):
function section9 (line 284) | def section9(data, bit, *nlist):
function section10 (line 325) | def section10(data, score, line, *etc):
function section11 (line 339) | def section11(data, n, turns_needed, penalty, question_n, message_n):
function section12 (line 362) | def section12(data, n, line):
function parse (line 374) | def parse(data, datafile):
FILE: adventure/game.py
class Game (line 23) | class Game(Data):
method __init__ (line 43) | def __init__(self, seed=None):
method random (line 61) | def random(self):
method choice (line 64) | def choice(self, seq):
method write (line 67) | def write(self, more):
method write_message (line 73) | def write_message(self, n):
method yesno (line 76) | def yesno(self, s, yesno_callback, casual=False):
method is_dark (line 85) | def is_dark(self):
method inventory (line 92) | def inventory(self):
method treasures (line 96) | def treasures(self):
method objects_here (line 100) | def objects_here(self):
method objects_at (line 103) | def objects_at(self, room):
method is_here (line 106) | def is_here(self, obj):
method is_finished (line 113) | def is_finished(self):
method start (line 118) | def start(self):
method start2 (line 134) | def start2(self, yes):
method move_to (line 157) | def move_to(self, newloc=None): #2
method move_dwarves (line 192) | def move_dwarves(self):
method describe_location (line 327) | def describe_location(self): #2000
method say_okay_and_finish (line 389) | def say_okay_and_finish(self, *ignored): #2009
method finish_turn (line 397) | def finish_turn(self, obj=None): #2600
method do_command (line 440) | def do_command(self, words):
method _do_command (line 446) | def _do_command(self, words):
method dispatch_command (line 514) | def dispatch_command(self, words): #19999
method dont_understand (line 628) | def dont_understand(self):
method i_see_no (line 639) | def i_see_no(self, thing):
method do_motion (line 645) | def do_motion(self, word): #8
method die_here (line 783) | def die_here(self): #90
method die (line 788) | def die(self): #99
method ask_verb_what (line 822) | def ask_verb_what(self, verb, *args): #8000
method write_default_message (line 839) | def write_default_message(self, verb, *args):
method i_carry (line 852) | def i_carry(self, verb): #8010
method t_carry (line 860) | def t_carry(self, verb, obj): #9010
method t_drop (line 914) | def t_drop(self, verb, obj): #9020
method t_say (line 980) | def t_say(self, verb, word): #9030
method i_unlock (line 987) | def i_unlock(self, verb): #8040 Handles "unlock" case as well
method t_unlock (line 1000) | def t_unlock(self, verb, obj): #9040 Handles "lock" case as well
method t_light (line 1071) | def t_light(self, verb, obj=None): #9070
method t_extinguish (line 1085) | def t_extinguish(self, verb, obj=None): #9080
method t_wave (line 1097) | def t_wave(self, verb, obj): #9090
method i_attack (line 1112) | def i_attack(self, verb): #9120
method t_attack (line 1133) | def t_attack(self, verb, obj): #9124 (but control goes to 9120 first)
method i_pour (line 1181) | def i_pour(self, verb): #9130
method t_pour (line 1187) | def t_pour(self, verb, obj):
method i_eat (line 1214) | def i_eat(self, verb): #8140
method t_eat (line 1220) | def t_eat(self, verb, obj): #9140
method i_drink (line 1232) | def i_drink(self, verb): #9150
method t_drink (line 1238) | def t_drink(self, verb, obj): #9150
method t_rub (line 1250) | def t_rub(self, verb, obj): #9160
method t_throw (line 1257) | def t_throw(self, verb, obj): #9170
method i_quit (line 1321) | def i_quit(self, verb): #8180
method t_find (line 1328) | def t_find(self, verb, obj): #9190
method i_inventory (line 1343) | def i_inventory(self, verb): #8200
method t_feed (line 1357) | def t_feed(self, verb, obj): #9210
method i_fill (line 1399) | def i_fill(self, verb): #9220
method t_fill (line 1404) | def t_fill(self, verb, obj):
method t_blast (line 1436) | def t_blast(self, verb, obj=None): #9230
method i_score (line 1452) | def i_score(self, verb): #8240
method i_fee (line 1462) | def i_fee(self, verb): #8250
method i_brief (line 1493) | def i_brief(self, verb): #8260
method i_read (line 1499) | def i_read(self, verb): #8270
method t_read (line 1509) | def t_read(self, verb, obj): #9270
method t_break (line 1533) | def t_break(self, verb, obj): #9280
method t_wake (line 1550) | def t_wake(self, verb, obj): #9290
method i_suspend (line 1558) | def i_suspend(self, verb):
method t_suspend (line 1563) | def t_suspend(self, verb, obj):
method i_hours (line 1582) | def i_hours(self, verb):
method resume (line 1586) | def resume(self, obj):
method should_offer_hint (line 1601) | def should_offer_hint(self, hint, obj): #40000
method start_closing_cave (line 1624) | def start_closing_cave(self): #10000
method close_cave (line 1639) | def close_cave(self): #11000
method wake_repository_dwarves (line 1664) | def wake_repository_dwarves(self): #19000
method compute_score (line 1668) | def compute_score(self, for_score_command=False): #20000
method score_and_exit (line 1717) | def score_and_exit(self):
FILE: adventure/model.py
class Move (line 7) | class Move(object):
method __repr__ (line 15) | def __repr__(self):
class Room (line 42) | class Room(object):
method __init__ (line 60) | def __init__(self):
method __repr__ (line 63) | def __repr__(self):
method is_forced (line 67) | def is_forced(self):
method is_aboveground (line 71) | def is_aboveground(self):
method is_before_hall_of_mists (line 75) | def is_before_hall_of_mists(self):
method is_after_hall_of_mists (line 79) | def is_after_hall_of_mists(self):
method is_dark (line 83) | def is_dark(self):
class Word (line 86) | class Word(object):
method __init__ (line 93) | def __init__(self):
method __repr__ (line 96) | def __repr__(self):
method __eq__ (line 99) | def __eq__(self, text):
method add_synonym (line 102) | def add_synonym(self, other):
class Object (line 107) | class Object(object):
method __init__ (line 110) | def __init__(self):
method __repr__ (line 122) | def __repr__(self):
method __hash__ (line 125) | def __hash__(self):
method __eq__ (line 128) | def __eq__(self, other):
method is_at (line 131) | def is_at(self, room):
method carry (line 134) | def carry(self):
method drop (line 138) | def drop(self, room):
method hide (line 142) | def hide(self):
method destroy (line 146) | def destroy(self):
class Message (line 149) | class Message(object):
method __str__ (line 153) | def __str__(self):
class Hint (line 156) | class Hint(object):
method __init__ (line 166) | def __init__(self):
class Dwarf (line 169) | class Dwarf(object):
method __init__ (line 173) | def __init__(self, room):
method start_at (line 177) | def start_at(self, room):
method can_move (line 181) | def can_move(self, move):
class Pirate (line 189) | class Pirate(Dwarf):
FILE: adventure/prompt.py
class ReprTriggeredPhrase (line 9) | class ReprTriggeredPhrase(object):
method __init__ (line 12) | def __init__(self, game, words):
method __repr__ (line 16) | def __repr__(self):
method __call__ (line 21) | def __call__(self, arg=None):
method __getattr__ (line 28) | def __getattr__(self, name):
function install_words (line 32) | def install_words(game):
FILE: adventure/tests/test_commands.py
class CommandTest (line 11) | class CommandTest(TestCase):
method setUp (line 13) | def setUp(self):
method test_intransitive_commands_should_not_throw_exceptions (line 19) | def test_intransitive_commands_should_not_throw_exceptions(self):
method test_transitive_commands_should_not_throw_exceptions (line 27) | def test_transitive_commands_should_not_throw_exceptions(self):
FILE: adventure/tests/test_data.py
class DataTest (line 9) | class DataTest(unittest.TestCase):
method setUp (line 11) | def setUp(self):
method test_long_description (line 17) | def test_long_description(self):
method test_long_description_expands_tabs (line 23) | def test_long_description_expands_tabs(self):
method test_short_description (line 27) | def test_short_description(self):
method test_object_message_expands_tabs (line 31) | def test_object_message_expands_tabs(self):
method test_hint (line 36) | def test_hint(self):
class ReprTest (line 48) | class ReprTest(unittest.TestCase):
method setUp (line 50) | def setUp(self):
method assertMove (line 56) | def assertMove(self, room_i, entry_i, s):
method test_move_repr_look_good (line 60) | def test_move_repr_look_good(self):
method test_move_repr_works_on_all_moves (line 73) | def test_move_repr_works_on_all_moves(self):
method test_room_repr (line 82) | def test_room_repr(self):
method test_object_repr (line 85) | def test_object_repr(self):
method test_word_repr (line 89) | def test_word_repr(self):
FILE: adventure/tests/test_walks.py
function load_tests (line 12) | def load_tests(loader, tests, pattern):
class ChdirTemp (line 24) | class ChdirTemp(object):
method setup (line 25) | def setup(self, doctest_object):
method teardown (line 30) | def teardown(self, doctest_object):
Condensed preview — 23 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (311K chars).
[
{
"path": ".gitignore",
"chars": 75,
"preview": ".coverage\nhtmlcov/\n*~\n__pycache__/\n*.pyc\n/MANIFEST\nbuild/\ndist/\n*.egg-info\n"
},
{
"path": "LICENSE.ASF-2",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 185,
"preview": "Welcome to the git repository for the Python 3 version of Adventure!\nThe project README is one level deeper, inside of t"
},
{
"path": "adventure/MANIFEST.in",
"chars": 18,
"preview": "include LICENSE.*\n"
},
{
"path": "adventure/README.txt",
"chars": 6289,
"preview": "This is a faithful port of the “Adventure” game to Python 3 from the\noriginal 1977 FORTRAN code by Crowther and Woods (i"
},
{
"path": "adventure/TODO.txt",
"chars": 80,
"preview": "\n* Test dropping into the secret canyon from the direction that gets no dragon.\n"
},
{
"path": "adventure/__init__.py",
"chars": 1173,
"preview": "\"\"\"The Adventure game.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as free software under the\nApache License, Version"
},
{
"path": "adventure/__main__.py",
"chars": 1326,
"preview": "\"\"\"Offer Adventure at a custom command prompt.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as free software under the"
},
{
"path": "adventure/data.py",
"chars": 14722,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"Parse the original PDP ``advent.dat`` file.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed a"
},
{
"path": "adventure/game.py",
"chars": 61027,
"preview": "\"\"\"How we keep track of the state of the game.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as free software under the"
},
{
"path": "adventure/model.py",
"chars": 4898,
"preview": "\"\"\"Classes representing Adventure game components.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as free software under"
},
{
"path": "adventure/prompt.py",
"chars": 1515,
"preview": "\"\"\"Routines that install Adventure commands for the Python prompt.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as fre"
},
{
"path": "adventure/tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "adventure/tests/syntax.txt",
"chars": 1727,
"preview": ">>> import adventure\n>>> adventure.play(seed=2)\nWELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?\n<BLANKLINE>\n>>> no\n"
},
{
"path": "adventure/tests/test_commands.py",
"chars": 1141,
"preview": "\"\"\"Test suite.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as free software under the\nApache License, Version 2.0 as "
},
{
"path": "adventure/tests/test_data.py",
"chars": 3321,
"preview": "\"\"\"Test suite.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as free software under the\nApache License, Version 2.0 as "
},
{
"path": "adventure/tests/test_walks.py",
"chars": 1060,
"preview": "\"\"\"Test suite.\n\nCopyright 2010-2015 Brandon Rhodes. Licensed as free software under the\nApache License, Version 2.0 as "
},
{
"path": "adventure/tests/vignettes.txt",
"chars": 40802,
"preview": ">>> import io\n>>> from itertools import cycle, islice\n\nThis file tests the behavior of the Adventure game in all sorts o"
},
{
"path": "adventure/tests/walkthrough1.txt",
"chars": 93838,
"preview": ">>> import adventure\n>>> adventure.play(seed=1)\nWELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?\n<BLANKLINE>\n>>> yes"
},
{
"path": "adventure/tests/walkthrough2.txt",
"chars": 34501,
"preview": ">>> import adventure\n>>> adventure.play(seed=2)\nWELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?\n<BLANKLINE>\n>>> no\n"
},
{
"path": "adventure/tests/walkthrough3.txt",
"chars": 8998,
"preview": ">>> import adventure\n>>> adventure.play(seed=4)\nWELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?\n<BLANKLINE>\n>>> no\n"
},
{
"path": "adventure/tests/walkthrough4.txt",
"chars": 9372,
"preview": ">>> import adventure\n>>> adventure.play(seed=4)\nWELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?\n<BLANKLINE>\n>>> no\n"
},
{
"path": "setup.py",
"chars": 1095,
"preview": "import os\nimport sys\nfrom distutils.core import setup\n\nif sys.version_info < (3,):\n print('\\nSorry, but Adventure can"
}
]
About this extraction
This page contains the full source code of the brandon-rhodes/python-adventure GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 23 files (291.5 KB), approximately 90.3k tokens, and a symbol index with 161 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.