1
! -------------------------------------------------------------------------
2
! Menus.h A library extension providing easier and better menus
6
! A menu is a tree of objects of class Option. A Menu is an Option which
7
! launches a fresh menu when chosen. To choose option O, send the
12
! So to start off a menu session, send this message to the top menu.
14
! Here's a simple menu structure:
16
! Menu "Instructions for playing Mordred";
17
! Menu -> "How to play adventure games";
18
! Option -> -> "Looking around"
19
! with description "I am your eyes and ears ...";
20
! Option -> -> "Taking and Dropping"
21
! with description "When you find items ...";
22
! Option -> "About the author"
23
! with description "The author was born in ...";
25
! Menus produced in this code are automatically divided into pages
26
! so that they'll always fit on the screen, whatever size the screen is
27
! and however many options there are.
29
! Note that since objects can always be moved about in play, it's easy
30
! to create new menu structures to fit the circumstances of the moment.
31
! (For example, a hints menu which gives hints only on currently open
34
! You can instead write a routine to receive the "description" message.
35
! Then the text printed when an option is chosen can also vary.
37
! If you return 2 from such a routine, then the game does not prompt
38
! the player to press a key before going back into the menu.
39
! If you return 3, then the whole menu is closed up immediately.
41
! Finally, you can always give your own "select" routine for an Option.
42
! The rules for return values are the same; what's different is that
43
! this way the screen will not be cleared and given a nice banner when
44
! the option is chosen. (Nothing visible will happen unless you do
45
! it yourself.) The SwitchOption class is an example of the kind of
46
! gadget you might want this for:
48
! Menu "Game settings";
49
! SwitchOption -> FullRoomD "full room descriptions" has on;
50
! SwitchOption -> WordyP "wordier prompts";
51
! SwitchOption -> AllowSavedG "allow saved games" has on;
53
! Choosing any of these switch-options flips them between on and off.
54
! In your program, you can test
56
! if (WordyP has on) ...
58
! and so forth to check the current state.
59
! -------------------------------------------------------------------------
65
! Then we are using library 6/1 or 6/2, which won't have defined these:
67
Constant NKEY__TX = " N = next option";
68
Constant PKEY__TX = "P = previous";
69
Constant QKEY1__TX = " Q = resume game";
70
Constant QKEY2__TX = "Q = previous menu";
71
Constant RKEY__TX = "RETURN = select option";
73
Constant NKEY1__KY = 'N';
74
Constant NKEY2__KY = 'n';
75
Constant PKEY1__KY = 'P';
76
Constant PKEY2__KY = 'p';
77
Constant QKEY1__KY = 'Q';
78
Constant QKEY2__KY = 'q';
87
Array ForUseByOptions -> 129;
89
#Iftrue #version_number==6;
91
@output_stream 3 ForUseByOptions;
100
[ bar_height page pages temp;
102
screen_width = 0->33;
107
#Iftrue #version_number==6;
110
temp = bar_height * char_height;
113
@split_window bar_height;
116
! Black out top line in reverse video:
119
#Iftrue #version_number==6;
122
style reverse; spaces(screen_width);
123
#Iftrue #version_number==6;
127
if (#version_number ~= 6 && standard_interpreter == 0)
130
{ ForUseByOptions-->0 = 128;
131
@output_stream 3 ForUseByOptions;
133
if (pages ~= 1) print " [", page, "/", pages, "]";
135
#Iftrue #version_number==6;
136
temp = 1 + (screen_width*char_width - 0-->24)/2;
138
temp = (screen_width - ForUseByOptions-->0)/2;
144
if (pages ~= 1) print " [", page, "/", pages, "]";
146
return ForUseByOptions-->0;
149
[; self.emblazon(1, 1, 1);
151
style roman; @set_window 0; font on; new_line; new_line;
153
if (self provides description)
154
return self.description();
156
"[No text written for this option.]^";
159
Class Menu class Option
161
[ count j obj pkey line oldline top_line bottom_line
162
page pages options top_option y x;
164
screen_width = 0->33;
165
screen_height = 0->32;
166
#Iftrue #version_number==6;
175
if (screen_height == 0 or 255) screen_height = 18;
176
screen_height = screen_height - 7;
179
objectloop (obj in self && obj ofclass Option) options++;
180
if (options == 0) return 2;
182
pages = options/screen_height;
183
if (options%screen_height ~= 0) pages++;
193
top_option = (page - 1) * screen_height;
195
self.emblazon(5 + options, page, pages);
197
#Iftrue #version_number==6;
198
x = 1 + char_width; y = 1 + char_height; @set_cursor y 1;
199
@set_font 4->j; spaces(screen_width); @set_font 1->j;
200
@set_cursor y x; print (string) NKEY__TX;
201
j = 1+screen_width*char_width - Menus_Measure(PKEY__TX) - char_width;
202
@set_cursor y j; print (string) PKEY__TX;
204
y = y + char_height; @set_cursor y 1;
205
@set_font 4->j; spaces(screen_width); @set_font 1->j;
206
@set_cursor y x; print (string) RKEY__TX;
207
if (sender ofclass Option) j = QKEY2__TX; else j = QKEY1__TX;
208
j = 1+screen_width*char_width - Menus_Measure(j) - char_width;
211
@set_cursor 2 1; spaces(screen_width);
212
@set_cursor 2 2; print (string) NKEY__TX;
213
j = screen_width-12; @set_cursor 2 j; print (string) PKEY__TX;
215
@set_cursor 3 1; spaces(screen_width);
216
@set_cursor 3 2; print (string) RKEY__TX;
217
j = screen_width-17; @set_cursor 3 j;
220
if (sender ofclass Option)
221
print (string) QKEY2__TX;
223
print (string) QKEY1__TX;
226
count = top_line; j = 0;
227
objectloop (obj in self && obj ofclass Option)
228
{ if (j >= top_option && j < (top_option + screen_height))
230
#Iftrue #version_number==6;
231
y = 1 + (count-1)*char_height;
232
x = 1 + 4*char_width;
243
bottom_line = count - 1;
247
{ ! Move or create the > cursor:
250
{ #Iftrue #version_number == 6;
251
x = 1 + 4*char_width;
252
count = top_line; j = 0;
253
objectloop (obj in self && obj ofclass Option)
254
{ if (j >= top_option && j < (top_option + screen_height))
255
{ if (j - top_option + top_line == oldline or line)
256
{ if (j - top_option + top_line == line)
258
y = 1 + (count-1)*char_height;
260
print (char) ' ', (name) obj, (char) ' ';
268
if (oldline~=0) { @set_cursor oldline 4; print " "; }
269
@set_cursor line 4; print ">";
274
@read_char 1 -> pkey;
276
if (pkey == 253 or 254)
278
x = (0-->27-->1 - 1) / char_width + 1;
279
y = (0-->27-->2 - 1) / char_height + 1;
280
if (y >= top_line && y <= bottom_line)
287
{ if (x <= screen_width / 2)
293
{ if (x <= screen_width / 2)
302
if (pkey == NKEY1__KY or NKEY2__KY or 130)
305
if (line > bottom_line)
308
{ if (page == pages) page = 1; else page++;
315
if (pkey == PKEY1__KY or PKEY2__KY or 129)
319
{ line = bottom_line;
324
+ (options % screen_height) - 1;
327
{ page--; line = top_line + screen_height - 1;
335
if (pkey==QKEY1__KY or QKEY2__KY or 27 or 131) break;
337
if (pkey==10 or 13 or 132)
339
objectloop (obj in self && obj ofclass Option)
340
{ if (count == top_option + line - top_line) break;
350
print "[Please press SPACE to continue.]^";
352
L__M(##Miscellany, 53);
354
@read_char 1 -> pkey;
361
if (sender ofclass Option) return 2;
363
#Iftrue #version_number==6;
369
@erase_window -1; @set_window 0;
370
#Iftrue #version_number==6;
373
new_line; new_line; new_line;
374
if (deadflag==0) <<Look>>;
378
Class SwitchOption class Option
380
[; print (object) self, " ";
381
if (self has on) print "(on)"; else print "(off)";
385
[; if (self has on) give self ~on; else give self on;
389
! ------------------------------------------------------------------------