~ubuntu-branches/ubuntu/vivid/inform/vivid

« back to all changes in this revision

Viewing changes to inform-6.31.1/manual/s44.html

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-05-26 22:09:44 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526220944-ba7phz0d1k4vo7wx
Tags: 6.31.1+dfsg-1
* Remove a considerable number of files from the package
  due to unacceptable licensing terms.
* Repair library symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 
2
<html>
 
3
<head>
 
4
<title>DM4 &#167;44: Case study: a library file for menus</title>
 
5
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 
6
<link rel="stylesheet" type="text/css" href="dm4.css">
 
7
</head>
 
8
<body>
 
9
<p class="navbar">
 
10
 <a href="index.html">home</a> /
 
11
 <a href="contents.html">contents</a> /
 
12
 <a href="ch7.html" title="Chapter VII: The Z-Machine">chapter VII</a> /
 
13
 <a href="s43.html" title="&#167;43: Pictures, sounds, blurbs and Blorb">prev</a> /
 
14
 <a href="s45.html" title="&#167;45: Limitations and getting around them">next</a> /
 
15
 <a href="dm4index.html">index</a>
 
16
</p>
 
17
<div class="page">
 
18
<a id="p336" name="p336"></a>
 
19
<h2>&#167;44 &nbsp; Case study: a library file for menus</h2>
 
20
 
 
21
<blockquote>Yes, all right, I won't do the menu &#8230; I don't think 
 
22
you realise how long it takes to do the menu, but no, it doesn't matter, 
 
23
I'll hang the picture now. If the menus are late for lunch it doesn't 
 
24
matter, the guests can all come and look at the picture till they 
 
25
are ready, right?<br>
 
26
&#8212; John Cleese and Connie Booth, <i>Fawlty Towers</i></blockquote>
 
27
 
 
28
<p class="normal"><span class="atleft"><img src="dm4-336_1.jpg" alt=""></span>
 
29
Sometimes one would like to provide a menu of text options, offered
 
30
to the player as a list on screen which can be rummaged through
 
31
with the cursor keys. For instance, the hints display in the &#8220;solid
 
32
gold&#8221; edition of Infocom's &#8216;Zork I&#8217; shows a list of 
 
33
&#8220;Invisiclues&#8221;: &#8220;Above Ground&#8221;, &#8220;The Cellar 
 
34
Area&#8221;, and so on. Moving a cursor to one of these options 
 
35
and pressing RETURN brings up a sub-menu of questions on the general 
 
36
topic chosen: for instance, &#8220;How do I cross the mountains?&#8221; 
 
37
Besides hints, many modern games use menu displays for instructions, 
 
38
background information, credits and release notes.</p>
 
39
 
 
40
<p class="indent">An optional library file called <tt>&quot;Menus.h&quot;</tt> 
 
41
is provided to manage such menus. If you want its facilities then, where 
 
42
you previously included <code>Verblib</code>, now write:</p>
 
43
 
 
44
<p class="lynxonly"></p>
 
45
<pre class="code">
 
46
Include &quot;Verblib&quot;;
 
47
Include &quot;Menus&quot;;
 
48
</pre>
 
49
 
 
50
<p class="normal">And this will make the features of <tt>Menus.h</tt> available. 
 
51
This section describes what these simple features are, and how they work, 
 
52
as an extended example of Z-machine programming.</p>
 
53
 
 
54
<p class="indent">The designer of this system began by noticing that 
 
55
menus and submenus and options fit together in a tree structure rather 
 
56
like the object tree:</p>
 
57
 
 
58
<p class="output">Hints for &#8216;Zork I&#8217; (menu)<br>
 
59
&nbsp; &nbsp; &rarr; Above Ground (submenu)<br>
 
60
&nbsp; &nbsp; &nbsp; &nbsp; &rarr; How do I cross the mountains? (option)<br>
 
61
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &rarr; <i>some text is revealed</i><br>
 
62
&nbsp; &nbsp; &rarr; The Cellar Area (submenu)<br>
 
63
&nbsp; &nbsp; &nbsp; &nbsp; &rarr; ...</p>
 
64
 
 
65
<a id="p337" name="p337"></a>
 
66
<p class="normal">The library file therefore defines two classes of object, 
 
67
<code>Menu</code> and <code>Option</code>. The short name of a menu is 
 
68
its title, while its children are the possible choices, which can be of 
 
69
either class. (So you can have as many levels of submenu as needed.) 
 
70
Since choosing an <code>Option</code> is supposed to produce some text, 
 
71
which is vaguely like examining objects, the <code>description</code> property of 
 
72
an <code>Option</code> holds the information revealed. So, for instance:</p>
 
73
 
 
74
<p class="lynxonly"></p>
 
75
<pre class="code">
 
76
Menu hints_menu &quot;Hints for Zork I&quot;;
 
77
Menu -&gt; &quot;Above Ground&quot;;
 
78
Option -&gt; -&gt; &quot;How do I cross the mountains?&quot;
 
79
  with description &quot;By ...&quot;;
 
80
Menu -&gt; &quot;The Cellar Area&quot;;
 
81
</pre>
 
82
 
 
83
<p class="normal">Note that such a structure can be rearranged in play 
 
84
just as the rest of the object tree can, which is convenient for &#8220;adaptive 
 
85
hints&#8221;, where the hints offered vary with the player's present travail.</p>
 
86
 
 
87
<p class="indent">How does this work? A menu or an option is chosen by 
 
88
being sent the message <code>select</code>. So the designer will launch 
 
89
the menu, perhaps in response to the player having typed &#8220;hints&#8221;, 
 
90
like so:</p>
 
91
 
 
92
<p class="lynxonly"></p>
 
93
<pre class="code">
 
94
[ HintsSub;
 
95
  hints_menu.select();
 
96
];
 
97
</pre>
 
98
 
 
99
<p class="normal">As the player browses through the menu, each menu sends 
 
100
the <code>select</code> message to the next one chosen, and so on. This already suggests 
 
101
that menus and options are basically similar, and in fact that's right: 
 
102
<code>Menu</code> is actually a subclass of <code>Option</code>, which 
 
103
is the more basic idea of the two.</p>
 
104
 
 
105
<p class="dotbreak">� � � � �</p>
 
106
 
 
107
<p class="normal">The actual code of <tt>Menus.h</tt> is slightly different 
 
108
from that given below, but only to fuss with dealing with early copies 
 
109
of the rest of the library, and to handle multiple languages. It begins 
 
110
with the class definition of <code>Option</code>, as follows:</p>
 
111
 
 
112
<p class="lynxonly"></p>
 
113
<pre class="code">
 
114
Class Option
 
115
 with select [;
 
116
          self.emblazon(1, 1, 1);
 
117
          @set_window 0; font on; style roman; new_line; new_line;
 
118
          if (self provides description) return self.description();
 
119
          &quot;[No text written for this option.]^&quot;;
 
120
      ],
 
121
</pre>
 
122
 
 
123
<a id="p338" name="p338"></a>
 
124
<p class="normal">The option sends itself the message <code>emblazon(1,1,1)</code> 
 
125
to clear the screen an put a bar of height 1 line at the top, containing 
 
126
the title of the option centred. The other two 1s declare that this 
 
127
is &#8220;page 1 of 1&#8221;: see below. Window 0 (the ordinary, lower 
 
128
window) is then selected; text reverts to its usual state of being
 
129
roman-style and using a variable-pitched font. The screen is now empty 
 
130
and ready for use, and the option expects to have a <code>description</code> 
 
131
property which actually does any printing that's required. To get back 
 
132
to the emblazoning:</p>
 
133
 
 
134
<p class="lynxonly"></p>
 
135
<pre class="code">
 
136
emblazon [ bar_height page pages temp;
 
137
    screen_width = 0-&gt;33;
 
138
    !   Clear screen:
 
139
    @erase_window -1;
 
140
    @split_window bar_height;
 
141
    !   Black out top line in reverse video:
 
142
    @set_window 1;
 
143
    @set_cursor 1 1;
 
144
    style reverse; spaces(screen_width);
 
145
    if (standard_interpreter == 0)
 
146
        @set_cursor 1 1;
 
147
    else {
 
148
        ForUseByOptions--&gt;0 = 128;
 
149
        @output_stream 3 ForUseByOptions;
 
150
        print (name) self;
 
151
        if (pages ~= 1) print &quot; [&quot;, page, &quot;/&quot;, pages, &quot;]&quot;;
 
152
        @output_stream -3;
 
153
        temp = (screen_width - ForUseByOptions--&gt;0)/2;
 
154
        @set_cursor 1 temp;
 
155
    }
 
156
    print (name) self;
 
157
    if (pages ~= 1) print &quot; [&quot;, page, &quot;/&quot;, pages, &quot;]&quot;;
 
158
    return ForUseByOptions--&gt;0;
 
159
];
 
160
</pre>
 
161
 
 
162
<p class="normal">That completes <code>Option</code>. However, since 
 
163
this code refers to a variable and an array, we had better write 
 
164
definitions of them:</p>
 
165
 
 
166
<p class="lynxonly"></p>
 
167
<pre class="code">
 
168
Global screen_width;
 
169
Global screen_height;
 
170
Array ForUseByOptions -&gt; 129;
 
171
</pre>
 
172
 
 
173
<p class="normal">(The other global variable, <code>screen_height</code>, 
 
174
will be used later. The variables are global because they will be needed 
 
175
by all of the menu objects.) The <code>emblazon</code> code checks 
 
176
to see if it's running on a standard interpreter. If so, it uses output 
 
177
stream 3 into an array to measure the length of text like &#8220;The
 
178
<a id="p339" name="p339"></a>
 
179
Cellars [2/3]&#8221; in order to centre it on the top line. If not, 
 
180
the text appears at the top left instead.</p>
 
181
 
 
182
<p class="indent">So much for <code>Option</code>. The definition of 
 
183
<code>Menu</code> is, inevitably, longer. It inherits <code>emblazon</code> 
 
184
from its superclass <code>Option</code>, but overrides the definition 
 
185
of <code>select</code> with something more elaborate:</p>
 
186
 
 
187
<p class="lynxonly"></p>
 
188
<pre class="code">
 
189
Class Menu class Option
 
190
 with select [ count j obj pkey line oldline top_line bottom_line
 
191
        page pages options top_option;
 
192
          screen_width = 0-&gt;33;
 
193
          screen_height = 0-&gt;32;
 
194
          if (screen_height == 0 or 255) screen_height = 18;
 
195
          screen_height = screen_height - 7;
 
196
</pre>
 
197
 
 
198
<p class="normal">The first task is to work out how much room the screen 
 
199
has to display options. The width and height, in characters, are read 
 
200
out of the story file's header area, where the interpreter has written 
 
201
them. In case the interpreter is <em>really</em> poor, we guess at 18 
 
202
if the height is claimed to be zero or 255; since this is a library 
 
203
file and will be widely used, it errs on the side of extreme caution.
 
204
Finally, 7 is subtracted because seven of the screen lines are occupied 
 
205
by the panel at the top and white space above and below the choices. 
 
206
The upshot is that <code>screen_height</code> is the actual maximum number 
 
207
of options to be offered per page of the menu. Next: how many options are 
 
208
available?</p>
 
209
 
 
210
<p class="lynxonly"></p>
 
211
<pre class="code">
 
212
          options = 0;
 
213
          objectloop (obj in self &amp;&amp; obj ofclass Option) options++;
 
214
          if (options == 0) return 2;
 
215
</pre>
 
216
 
 
217
<p class="normal">(Note that a <code>Menu</code> is also an <code>Option</code>.) 
 
218
We can now work out how many pages will be needed.</p>
 
219
 
 
220
<p class="lynxonly"></p>
 
221
<pre class="code">
 
222
          pages = options/screen_height;
 
223
          if (options%screen_height ~= 0) pages++;
 
224
          top_line = 6;
 
225
          page = 1;
 
226
          line = top_line;
 
227
</pre>
 
228
 
 
229
<p class="normal"><code>top_line</code> is the highest screen line used 
 
230
to display an option: line 6. The local variables <code>page</code> and 
 
231
<code>line</code> show which line on which page the current selection
 
232
arrow points to, so we're starting at the top line of page 1.</p>
 
233
 
 
234
<p class="lynxonly"></p>
 
235
<pre class="code">
 
236
          .ReDisplay;
 
237
          top_option = (page - 1) * screen_height;
 
238
</pre>
 
239
 
 
240
<a id="p340" name="p340"></a>
 
241
<p class="normal">This is the option number currently selected, counting 
 
242
from zero. We display the three-line black strip at the top of the 
 
243
screen, using <code>emblazon</code> to create the upper window:</p>
 
244
 
 
245
<p class="lynxonly"></p>
 
246
<pre class="code">
 
247
          self.emblazon(7 + count, page, pages);
 
248
          @set_cursor 2 1; spaces(screen_width);
 
249
          @set_cursor 2 2; print &quot;N = next subject&quot;;
 
250
          j = screen_width-12; @set_cursor 2 j; print &quot;P = previous&quot;;
 
251
          @set_cursor 3 1; spaces(screen_width);
 
252
          @set_cursor 3 2; print &quot;RETURN = read subject&quot;;
 
253
          j = screen_width-17; @set_cursor 3 j;
 
254
</pre>
 
255
 
 
256
<p class="normal">The last part of the black strip to print is the 
 
257
one offering Q to quit:</p>
 
258
 
 
259
<p class="lynxonly"></p>
 
260
<pre class="code">
 
261
          if (sender ofclass Option) print &quot;Q = previous menu&quot;;
 
262
          else print &quot;  Q = resume game&quot;;
 
263
          style roman;
 
264
</pre>
 
265
 
 
266
<p class="normal">The point of this is that pressing Q only takes us 
 
267
back to the previous menu if we're inside the hierarchy, i.e., if the 
 
268
message <code>select</code> was sent to this <code>Menu</code> by another 
 
269
<code>Option</code>; whereas if not, Q takes us out of the menu altogether. 
 
270
Next, we count through those options appearing on the current page 
 
271
and print their names.</p>
 
272
 
 
273
<p class="lynxonly"></p>
 
274
<pre class="code">
 
275
          count = top_line; j = 0;
 
276
          objectloop (obj in self &amp;&amp; obj ofclass Option) {
 
277
              if (j &gt;= top_option &amp;&amp; j &lt; (top_option+screen_height)) {
 
278
                  @set_cursor count 6;
 
279
                  print (name) obj;
 
280
                  count++;
 
281
              }
 
282
              j++;
 
283
          }
 
284
          bottom_line = count - 1;
 
285
</pre>
 
286
 
 
287
<p class="normal">Note that the name of the option begins on column 6 
 
288
of each line. The player's current selection is shown with a cursor 
 
289
<code>&gt;</code> appearing in column 4:</p>
 
290
 
 
291
<p class="lynxonly"></p>
 
292
<pre class="code">
 
293
          oldline = 0;
 
294
          for (::) {
 
295
              ! Move or create the &gt; cursor:
 
296
              if (line ~= oldline) {
 
297
                  if (oldline ~= 0) {
 
298
                      @set_cursor oldline 4; print &quot; &quot;;
 
299
                  }
 
300
                  @set_cursor line 4; print &quot;&gt;&quot;;<a id="p341" name="p341"></a>
 
301
              }
 
302
              oldline = line;
 
303
</pre>
 
304
 
 
305
<p class="normal">Now we wait for a single key-press from the player:</p>
 
306
 
 
307
<p class="lynxonly"></p>
 
308
<pre class="code">
 
309
              @read_char 1 -&gt; pkey;
 
310
              if (pkey == 'N' or 'n' or 130) {
 
311
                  ! Cursor down:
 
312
                  line++;
 
313
                  if (line &gt; bottom_line) {
 
314
                      line = top_line;
 
315
                      if (pages &gt; 1) {
 
316
                          if (page == pages) page = 1; else page++;
 
317
                          jump ReDisplay;
 
318
                      }
 
319
                  }
 
320
                  continue;
 
321
              }
 
322
</pre>
 
323
 
 
324
<p class="normal">130 is the ZSCII code for &#8220;cursor down key&#8221;. 
 
325
Note that if the player tries to move the cursor off the bottom of the 
 
326
list, and there's at least one more page, we jump right out of the loop 
 
327
and back to <code>ReDisplay</code> to start again from the top of the 
 
328
next page. Handling the &#8220;previous&#8221; option is very similar, 
 
329
and then:</p>
 
330
 
 
331
<p class="lynxonly"></p>
 
332
<pre class="code">
 
333
              if (pkey == 'Q' or 'q' or 27 or 131) break;
 
334
</pre>
 
335
 
 
336
<p class="normal">Thus pressing lower or upper case Q, escape (ZSCII 27) 
 
337
or cursor left (ZSCII 131) all have the same effect: to break out of 
 
338
the for loop. Otherwise, one can press RETURN or cursor right to select 
 
339
an option:</p>
 
340
 
 
341
<p class="lynxonly"></p>
 
342
<pre class="code">
 
343
              if (pkey == 10 or 13 or 132) {
 
344
                  count = 0;
 
345
                  objectloop (obj in self &amp;&amp; obj ofclass Option) {
 
346
                      if (count == top_option + line - top_line) break;
 
347
                      count++;
 
348
                  }
 
349
                  switch (obj.select()) {
 
350
                      2: jump ReDisplay;
 
351
                      3: jump ExitMenu;
 
352
                  }
 
353
                  print &quot;[Please press SPACE to continue.]^&quot;;
 
354
                  @read_char 1 -&gt; pkey;
 
355
                  jump ReDisplay;
 
356
              }
 
357
          }
 
358
</pre>
 
359
 
 
360
<a id="p342" name="p342"></a>
 
361
<p class="normal">(No modern interpreter should ever give 10 for the 
 
362
key-code of RETURN, which is ZSCII 13. Once again, the library file 
 
363
is erring on the side of extreme caution.) An option's <code>select</code> 
 
364
routine can return three different values for different effects:</p>
 
365
 
 
366
<p class="lynxonly"></p>
 
367
<div class="clump"><table border="1" align="center" style="text-align:center">
 
368
<tr><td>2</td><td>Redisplay the menu page that selected me</td></tr>
 
369
<tr><td>3</td><td>Exit from that menu page</td></tr>
 
370
<tr><td>anything else</td><td>Wait for SPACE, then redisplay that menu page</td></tr>
 
371
</table></div>
 
372
 
 
373
<p class="normal">Finally, the exit from the menu, either because the 
 
374
player typed Q, escape, etc., or because the selected option returned 3:</p>
 
375
 
 
376
<p class="lynxonly"></p>
 
377
<pre class="code">
 
378
          .ExitMenu;
 
379
          if (sender ofclass Option) return 2;
 
380
          font on; @set_cursor 1 1;
 
381
          @erase_window -1; @set_window 0;
 
382
          new_line; new_line; new_line;
 
383
          if (deadflag == 0) &lt;&lt;Look&gt;&gt;;
 
384
          return 2;
 
385
      ];
 
386
</pre>
 
387
 
 
388
<p class="normal">And that's it. If this menu was the highest-level one, it 
 
389
needs to resume the game politely, by clearing the screen and performing 
 
390
a <code>Look</code> action. If not, then it needs only to return 2, 
 
391
indicating &#8220;redisplay the menu page that selected me&#8221;: 
 
392
that is, the menu one level above.</p>
 
393
 
 
394
<p class="indent">The only remaining code in <tt>&quot;Menus.h&quot;</tt> 
 
395
shows some of the flexibility of the above design, by defining a special 
 
396
type of option:</p>
 
397
 
 
398
<p class="lynxonly"></p>
 
399
<pre class="code">
 
400
Class SwitchOption class Option
 
401
  with short_name [;
 
402
           print (object) self, &quot; &quot;;
 
403
           if (self has on) print &quot;(on)&quot;; else print &quot;(off)&quot;;
 
404
           rtrue;
 
405
       ],
 
406
       select [;
 
407
           if (self has on) give self ~on; else give self on;
 
408
           return 2;
 
409
       ];
 
410
</pre>
 
411
 
 
412
<p class="normal">Here is an example of <code>SwitchOptions</code> in 
 
413
use:</p>
 
414
 
 
415
<p class="lynxonly"></p>
 
416
<pre class="code">
 
417
Menu settings &quot;Game settings&quot;;
 
418
SwitchOption -&gt; FullRoomD   &quot;full room descriptions&quot; has on;
 
419
SwitchOption -&gt; WordyP      &quot;wordier prompts&quot;;
 
420
SwitchOption -&gt; AllowSavedG &quot;allow saved games&quot; has on;
 
421
</pre>
 
422
 
 
423
<a id="p343" name="p343"></a>
 
424
<p class="normal">So each option has the attribute <code>on</code> only if 
 
425
currently set. In the menu, the option <code>FullRoomD</code> is displayed 
 
426
either as &#8220;full room descriptions (on)&#8221; or &#8220;full room 
 
427
descriptions (off)&#8221;, and selecting it switches the state, like a 
 
428
light switch. The rest of the code can then perform tests like so:</p>
 
429
 
 
430
<p class="lynxonly"></p>
 
431
<pre class="code">
 
432
if (AllowSavedG hasnt on) &quot;That spell is forbidden.&quot;;
 
433
</pre>
 
434
 
 
435
<p class="dotbreak">� � � � �</p>
 
436
 
 
437
<p class="lynxonly"></p>
 
438
<table>
 
439
<tr><td colspan="2"><small><i>Appearance of the final menu on a screen 64 characters wide:</i></small></td></tr>
 
440
<tr><td valign="top"><small><i>line 1</i></small></td><td valign="top"><tt>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Hints for Zork I [1/2]</tt></td></tr>
 
441
<tr><td valign="top"><small><i>line 2</i></small></td><td valign="top"><tt>N = next subject &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P = previous</tt></td></tr>
 
442
<tr><td valign="top"><small><i>line 3</i></small></td><td valign="top"><tt>RETURN = read subject &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Q = resume game</tt></td></tr>
 
443
<tr><td valign="top"><small><i>line 4</i></small></td><td valign="top"><tt>&nbsp;</tt></td></tr>
 
444
<tr><td valign="top"><small><i>line 5</i></small></td><td valign="top"><tt>&nbsp;</tt></td></tr>
 
445
<tr><td valign="top"><small><i>line 6</i></small></td><td valign="top"><tt>&nbsp; &nbsp; Above Ground</tt></td></tr>
 
446
<tr><td valign="top"><small><i>line 7</i></small></td><td valign="top"><tt>&nbsp; &gt; The Cellar Area</tt></td></tr>
 
447
<tr><td valign="top"><small><i>line 8</i></small></td><td valign="top"><tt>&nbsp; &nbsp; The Maze</tt></td></tr>
 
448
<tr><td valign="top"><small><i>line 9</i></small></td><td valign="top"><tt>&nbsp; &nbsp; The Round Room Area</tt></td></tr>
 
449
</table>
 
450
 
 
451
<p class="aside"><span class="warning"><b>&#8226;</b>
 
452
<b>REFERENCES</b></span><br>
 
453
Because there was a crying need for good menus in the early days of 
 
454
Inform, there are now numerous library extensions to support menus 
 
455
and interfaces built from them. The original such was L. Ross Raszewski's 
 
456
<tt>&quot;domenu.h&quot;</tt>, which provides a core of basic routines. 
 
457
<tt>&quot;AltMenu.h&quot;</tt> then uses these routines to emulate the 
 
458
same menu structures coded up in this section. <tt>&quot;Hints.h&quot;</tt> 
 
459
employs them for Invisiclues-style hints; <tt>&quot;manual.h&quot;</tt> 
 
460
for browsing books and manuals; <tt>&quot;converse.h&quot;</tt> for 
 
461
menu-based conversations with people, similar to those in graphical 
 
462
adventure games. Or indeed to those in Adam Cadre's game &#8216;Photopia&#8217;, 
 
463
and Adam has kindly extracted his menu-based conversational routines 
 
464
into an example program called <tt>&quot;phototalk.inf&quot;</tt>.
 
465
For branching menus, such as a tree of questions and answers, try 
 
466
Chris Klimas's <tt>&quot;branch.h&quot;</tt>. To put a menu of commands 
 
467
at the status line of a typical game, try Adam Stark's <tt>&quot;action.h&quot;</tt>.</p>
 
468
 
 
469
</div>
 
470
<p class="navbar">
 
471
 <a href="index.html">home</a> /
 
472
 <a href="contents.html">contents</a> /
 
473
 <a href="ch7.html" title="Chapter VII: The Z-Machine">chapter VII</a> /
 
474
 <a href="s43.html" title="&#167;43: Pictures, sounds, blurbs and Blorb">prev</a> /
 
475
 <a href="s45.html" title="&#167;45: Limitations and getting around them">next</a> /
 
476
 <a href="dm4index.html">index</a>
 
477
</p>
 
478
</body>
 
479
</html>
 
480