-
Notifications
You must be signed in to change notification settings - Fork 40
/
rooms.rst
215 lines (157 loc) · 6.43 KB
/
rooms.rst
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
Rooms
=====
Many adventure games - but not all - have a concept of "rooms". A player can
explore rooms with some standard movement commands, perhaps finding interesting
items that they can use or characters they can speak to. Note that despite the
name, a room doesn't have to be a room of a house. You could use rooms to
describe any concept of location, in order to tell your story:
* Drifting in space
* On top of a hill
* Underneath the floorboards
* Nowhere
Adventurelib provides a helper object called ``Room``, that can be used within
your program. You don't have to use this object in order to create the
impression of rooms though. You can do it with creative use of ``@when``
functions.
Creating a room
---------------
Rooms are created by passing a description. Rich descriptions that convey a
story to the user are very important to make your text adventure immersive,
so try to write at least a couple of sentences. ::
from adventurelib import *
space = Room("""
You are drifting in space. It feels very cold.
A slate-blue spaceship sits completely silently to your left,
its airlock open and waiting.
""")
spaceship = Room("""
The bridge if the spaceship is shiny and white, with thousands
of small, red, blinking lights.
""")
Next you'll want the ability to move between rooms. adventurelib doesn't track
what room the player is in; this is your responsibility!::
# current_room will be a global variable. Let's start out in
# space, so assign the 'space' room from above.
current_room = space
@when('enter airlock')
def enter_spaceship():
# To set a global variable from within a function you have
# to include the 'global' keyword, to avoid creating a
# local variable instead.
global current_room
# Got to check if this action can be done here
if current_room is not space:
print('There is no airlock here.')
return
current_room = spaceship
# You should include some narrative for every action to
# ensure the transition doesn't feel abrupt.
print(
"You heave yourself into the airlock and slam your " +
"hand on the button to close the outer door."
)
# Show the room description to indicate we have arrived.
print(current_room)
Storing attributes on rooms
---------------------------
Part of the reason for rooms is to have different objects or contexts for the
story. Some actions could only be possible in some rooms. You can assign
arbitrary attribute names to an object in order to track the state of a room
or what actions can be performed there. You can also set attributes on the
``Room`` object, which apply for all rooms::
Room.can_scream = True # The default for all rooms
space.can_scream = False # Set a value for a specific room.
@when('scream')
def scream():
if current_room.can_scream:
print(
"You unleash a piercing shriek that " +
"reverberates around you."
)
else:
print(
"You try to yell but there's no sound " +
"in the vacuum of space."
)
If you access an attribute that doesn't exist on a room, an ``AttributeError``
will be raised, so ensure that you either set an attribute on every single
room or set a default value on ``Room``.
Directions and exits
--------------------
Many text adventure games let players explore a system of rooms freely, using
common commands such as ``north``, ``south``, ``east`` and ``west``.
``Room`` objects support these compass point directions by default. If you
assign a room as the ``north`` attribute of another room, then you can traverse
this relationship. ::
space.north = spaceship
Then one could access the room to the north of the current room using normal
attribute access::
current_room.north
The key feature of the directions system is that these references are
**bi-directional**. adventurelib knows that ``north`` is the opposite of
``south``, so these relationships automatically hold::
>>> space.north is spaceship
True
>>> spaceship.south is space
True
Exits
-----
Rooms have a couple of methods that allow you to query what exits they have.
These can be useful when writing commands that use the room layout (such as
moving or looking in a direction).
.. function:: room.exit(direction)
Get the Room that is linked in direction (eg. ``north``). Returns ``None``
if there is no room in that direction.
.. function:: room.exits()
Get a list of direction names where a direction is set.
Moving between rooms
--------------------
To follow the links you've defined you could define separate ``north``,
``south``, ``east`` and ``west`` handlers - but the code would be mostly the
same, and this is annoying to type and make changes to.
Instead, we can define one function and use several different ``@when`` lines
to define the directions we will go. Each one will pass a direction in which
to go.::
@when('north', direction='north')
@when('south', direction='south')
@when('east', direction='east')
@when('west', direction='west')
def go(direction):
global current_room
room = current_room.exit(direction)
if room:
current_room = room
print(f'You go {direction}.')
look()
Then in game::
> north
You go north.
There is a polar bear here.
> south
You go south.
It is a bright, sunny day.
These can be some of the most heavily used command, so you could also provide
alias commands ``n``, ``s``, ``e`` and ``w`` as a convenience::
@when('north', direction='north')
@when('south', direction='south')
@when('east', direction='east')
@when('west', direction='west')
@when('n', direction='north')
@when('s', direction='south')
@when('e', direction='east')
@when('w', direction='west')
def go(direction):
...
Adding more directions
----------------------
While ``north``, ``south``, ``east`` and ``west`` are built into adventurelib,
you don't have to use them. You can also register new directions, so long as
you give an opposite. You would typically do this at the top of the file,
before you define any rooms::
Room.add_direction('up', 'down')
Room.add_direction('enter', 'exit')
tent = Room(...)
camp = Room(...)
river = Room(...)
camp.enter = tent
camp.down = river