Import v6.12.6 of the Inform 6 standard library
[informlib.git] / verblib.h
1 ! ==============================================================================
2 !   VERBLIB:  Front end to standard verbs library.
3 !
4 !   Supplied for use with Inform 6 -- Release 6.12.3 -- Serial number 190320
5 !
6 !   Copyright Graham Nelson 1993-2004 and David Griffith 2012-2019
7 !
8 !   This file is free software: you can redistribute it and/or modify
9 !   it under the terms of the GNU Affero General Public License as
10 !   published by the Free Software Foundation, either version 3 of the
11 !   License, or (at your option) any later version.
12 !
13 !   This file is distributed in the hope that it will be useful, but
14 !   WITHOUT ANY WARRANTY; without even the implied warranty of
15 !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 !   Affero General Public License for more details.
17 !
18 !   You should have received a copy of the GNU Affero General Public
19 !   License along with this program. If not, see
20 !   https://gnu.org/licenses/
21 !
22 !   In your game file, Include three library files in this order:
23 !       Include "parser";
24 !       Include "verblib";
25 !       Include "grammar";
26 ! ==============================================================================
27
28 System_file;
29
30 #Ifdef          LIBRARY_STAGE;
31 #Iffalse        LIBRARY_STAGE >= AFTER_VERBLIB; ! if not already included
32 #Iftrue         LIBRARY_STAGE == AFTER_PARSER;  ! if okay to include it
33
34 ! ------------------------------------------------------------------------------
35
36 Default AMUSING_PROVIDED    1;
37 Default MAX_CARRIED         100;
38 Default MAX_SCORE           0;
39 Default NUMBER_TASKS        1;
40 Default OBJECT_SCORE        4;
41 Default ROOM_SCORE          5;
42 Default SACK_OBJECT         0;
43 Default TASKS_PROVIDED      1;
44
45 #Ifndef task_scores;
46 Array  task_scores -> 0 0 0 0;
47 #Endif;
48
49 Array  task_done -> NUMBER_TASKS;
50
51 #Ifndef LibraryMessages;
52 Object LibraryMessages;
53 #Endif;
54
55 #Ifndef NO_PLACES;
56 [ ObjectsSub; Objects1Sub(); ];
57 [ PlacesSub;  Places1Sub(); ];
58 #Endif; ! NO_PLACES
59
60 ! ------------------------------------------------------------------------------
61 ! Banner(), VersionSub(), and RunTimeError() are preempted by LanguageBanner(),
62 ! LanguageVersionSub(), and LanguageError() respectfully.  When converting
63 ! this library to support a different natural language, these three latter
64 ! functions should be created rather than editing this file.
65 ! ------------------------------------------------------------------------------
66
67 [ Banner i;
68     #Ifdef LanguageBanner;
69     LanguageBanner();
70     i = 0;  ! suppress warning
71     #Ifnot;
72     if (Story) {
73         #Ifdef TARGET_ZCODE;
74         #IfV5; style bold; #Endif;
75         print "^", (string) Story;
76         #IfV5; style roman; #Endif;
77         #Ifnot; ! TARGET_GLULX;
78         glk_set_style(style_Header);
79         print "^", (string) Story;
80         glk_set_style(style_Normal);
81         #Endif; ! TARGET_
82     }
83     if (Headline) print (string) Headline;
84     #Ifdef TARGET_ZCODE;
85     print "Release ", (HDR_GAMERELEASE-->0) & $03ff, " / Serial number ";
86     for (i=0 : i<6 : i++) print (char) HDR_GAMESERIAL->i;
87     #Ifnot; ! TARGET_GLULX;
88     print "Release ";
89     @aloads ROM_GAMERELEASE 0 i;
90     print i;
91     print " / Serial number ";
92     for (i=0 : i<6 : i++) print (char) ROM_GAMESERIAL->i;
93     #Endif; ! TARGET_
94     new_line;
95     #Endif; ! LanguageBanner
96 ];
97
98 [ VersionSub ix;
99     #Ifdef LanguageVersionSub;
100     LanguageVersionSub();
101     ix = 0;  ! suppress warning
102     #Ifnot;
103     Banner();
104     #Ifdef TARGET_ZCODE;
105     ix = 0; ! shut up compiler warning
106     if (standard_interpreter > 0) {
107         print "Standard interpreter ", standard_interpreter/256, ".", standard_interpreter%256,
108             " (", HDR_TERPNUMBER->0;
109         #Iftrue (#version_number == 6);
110         print (char) '.', HDR_TERPVERSION->0;
111         #Ifnot;
112         print (char) HDR_TERPVERSION->0;
113         #Endif;
114         print ") / ";
115         }
116     else {
117         print "Interpreter ", HDR_TERPNUMBER->0, " Version ";
118         #Iftrue (#version_number == 6);
119         print HDR_TERPVERSION->0;
120         #Ifnot;
121         print (char) HDR_TERPVERSION->0;
122         #Endif;
123         print " / ";
124     }
125
126     #Ifnot; ! TARGET_GLULX;
127     @gestalt 1 0 ix;
128     print "Interpreter version ", ix / $10000, ".", (ix & $FF00) / $100,
129       ".", ix & $FF, " / ";
130     @gestalt 0 0 ix;
131     print "VM ", ix / $10000, ".", (ix & $FF00) / $100, ".", ix & $FF, " / ";
132     #Endif; ! TARGET_;
133     print "Library serial number ", (string) LibSerial, "^";
134     #Ifdef LanguageVersion;
135     print (string) LanguageVersion, "^";
136     #Endif; ! LanguageVersion
137     #Endif; ! LanguageVersionSub
138 ];
139
140 [ RunTimeError n p1 p2;
141     #Ifdef LanguageError;
142     LanguageError(n, p1, p2);
143     #Ifnot;
144     #Ifdef DEBUG;
145     print "** Library error ", n, " (", p1, ", ", p2, ") **^** ";
146     switch (n) {
147       1:    print "preposition not found (this should not occur)";
148       2:    print "Property value not routine or string: ~", (property) p2, "~ of ~", (name) p1,
149                   "~ (", p1, ")";
150       3:    print "Entry in property list not routine or string: ~", (property) p2, "~ list of ~",
151                   (name) p1, "~ (", p1, ")";
152       4:    print "Too many timers/daemons are active simultaneously.
153                   The limit is the library constant MAX_TIMERS
154                   (currently ", MAX_TIMERS, ") and should be increased";
155       5:    print "Object ~", (name) p1, "~ has no ~", (property) p2, "~ property";
156       7:    print "The object ~", (name) p1, "~ can only be used as a player object if it has
157                   the ~number~ property";
158       8:    print "Attempt to take random entry from an empty table array";
159       9:    print p1, " is not a valid direction property number";
160       10:   print "The player-object is outside the object tree";
161       11:   print "The room ~", (name) p1, "~ has no ~", (property) p2, "~ property";
162       12:   print "Tried to set a non-existent pronoun using SetPronoun";
163       13:   print "A 'topic' token can only be followed by a preposition";
164       14:   print "Overflowed buffer limit of ", p1, " using '@@64output_stream 3' ", (string) p2;
165       15:   print "LoopWithinObject broken because the object ", (name) p1, " was moved while the loop passed through it.";
166       16:   print "Attempt to use illegal narrative_voice of ", p1, ".";
167       default:
168             print "(unexplained)";
169     }
170     " **";
171     #Ifnot;
172     "** Library error ", n, " (", p1, ", ", p2, ") **";
173     #Endif; ! DEBUG
174     #Endif; ! LanguageError
175 ];
176
177 ! ----------------------------------------------------------------------------
178 !  The WriteListFrom routine, a flexible object-lister taking care of
179 !  plurals, inventory information, various formats and so on.  This is used
180 !  by everything in the library which ever wants to list anything.
181 !
182 !  If there were no objects to list, it prints nothing and returns false;
183 !  otherwise it returns true.
184 !
185 !  o is the object, and style is a bitmap, whose bits are given by:
186 ! ----------------------------------------------------------------------------
187
188
189 Constant NEWLINE_BIT   $0001;       ! New-line after each entry
190 Constant INDENT_BIT    $0002;       ! Indent each entry by depth
191 Constant FULLINV_BIT   $0004;       ! Full inventory information after entry
192 Constant ENGLISH_BIT   $0008;       ! English sentence style, with commas and and
193 Constant RECURSE_BIT   $0010;       ! Recurse downwards with usual rules
194 Constant ALWAYS_BIT    $0020;       ! Always recurse downwards
195 Constant TERSE_BIT     $0040;       ! More terse English style
196 Constant PARTINV_BIT   $0080;       ! Only brief inventory information after entry
197 Constant DEFART_BIT    $0100;       ! Use the definite article in list
198 Constant WORKFLAG_BIT  $0200;       ! At top level (only), only list objects
199                                     ! which have the "workflag" attribute
200 Constant ISARE_BIT     $0400;       ! Print " is" or " are" before list
201 Constant CONCEAL_BIT   $0800;       ! Omit objects with "concealed" or "scenery":
202                                     ! if WORKFLAG_BIT also set, then does _not_
203                                     ! apply at top level, but does lower down
204 Constant NOARTICLE_BIT $1000;       ! Print no articles, definite or not
205 Constant ID_BIT        $2000;       ! Print object id after each entry
206
207 [ NextEntry o odepth;
208     for (::) {
209         o = sibling(o);
210         if (o == 0) return 0;
211         if (lt_value && o.list_together ~= lt_value) continue;
212         if (c_style & WORKFLAG_BIT && odepth==0 && o hasnt workflag) continue;
213         if (c_style & CONCEAL_BIT && (o has concealed || o has scenery)) continue;
214         return o;
215     }
216 ];
217
218 [ WillRecurs o;
219     if (c_style & ALWAYS_BIT) rtrue;
220     if (c_style & RECURSE_BIT == 0) rfalse;
221     if ((o has transparent or supporter) || (o has container && o has open)) rtrue;
222     rfalse;
223 ];
224
225 [ ListEqual o1 o2;
226     if (child(o1) && WillRecurs(o1)) rfalse;
227     if (child(o2) && WillRecurs(o2)) rfalse;
228     if (c_style & (FULLINV_BIT + PARTINV_BIT)) {
229         if ((o1 hasnt worn && o2 has worn) || (o2 hasnt worn && o1 has worn)) rfalse;
230         if ((o1 hasnt light && o2 has light) || (o2 hasnt light && o1 has light)) rfalse;
231         if (o1 has container) {
232             if (o2 hasnt container) rfalse;
233             if ((o1 has open && o2 hasnt open) || (o2 has open && o1 hasnt open))
234                 rfalse;
235         }
236         else if (o2 has container)
237             rfalse;
238     }
239     return Identical(o1, o2);
240 ];
241
242 [ SortTogether obj value;
243     ! print "Sorting together possessions of ", (object) obj, " by value ", value, "^";
244     ! for (x=child(obj) : x : x=sibling(x))
245     !     print (the) x, " no: ", x, " lt: ", x.list_together, "^";
246     while (child(obj)) {
247         if (child(obj).list_together ~= value) move child(obj) to out_obj;
248         else                                   move child(obj) to in_obj;
249     }
250     while (child(in_obj))  move child(in_obj) to obj;
251     while (child(out_obj)) move child(out_obj) to obj;
252 ];
253
254 [ SortOutList obj i k l;
255     !  print "^^Sorting out list from ", (name) obj, "^  ";
256     !  for (i=child(location) : i : i=sibling(i))
257     !      print (name) i, " --> ";
258     !  new_line;
259
260   .AP_SOL;
261
262     for (i=obj : i : i=sibling(i)) {
263         k = i.list_together;
264         if (k ~= 0) {
265             ! print "Scanning ", (name) i, " with lt=", k, "^";
266             for (i=sibling(i) : i && i.list_together == k :) i = sibling(i);
267             if (i == 0) rfalse;
268             ! print "First not in block is ", (name) i, " with lt=", i.list_together, "^";
269             for (l=sibling(i) : l : l=sibling(l))
270                 if (l.list_together == k) {
271                     SortTogether(parent(obj), k);
272                     ! print "^^After ST:^  ";
273                     ! for (i=child(location) : i : i=sibling(i))
274                     !     print (name) i, " --> ";
275                     ! new_line;
276                     obj = child(parent(obj));
277                     jump AP_SOL;
278                 }
279         }
280     }
281 ];
282
283 #Ifdef TARGET_ZCODE;
284
285 [ Print__Spaces n;         ! To avoid a bug occurring in Inform 6.01 to 6.10
286     if (n == 0) return;
287     spaces n;
288 ];
289
290 #Ifnot; ! TARGET_GLULX;
291
292 [ Print__Spaces n;
293     while (n > 0) {
294         @streamchar ' ';
295         n = n - 1;
296     }
297 ];
298
299 #Endif; ! TARGET_
300
301 [ WriteListFrom o style depth
302     s1 s2 s3 s4 s5 s6;
303
304     if (o == nothing) return 0;
305
306     s1 = c_style;      s2 = lt_value;   s3 = listing_together;
307     s4 = listing_size; s5 = wlf_indent; s6 = inventory_stage;
308
309     if (o == child(parent(o))) {
310         SortOutList(o);
311         o = child(parent(o));
312     }
313     c_style = style;
314     wlf_indent = 0;
315     if (WriteListR(o, depth) == 0) return 0;
316
317     c_style = s1;      lt_value = s2;   listing_together = s3;
318     listing_size = s4; wlf_indent = s5; inventory_stage = s6;
319     rtrue;
320 ];
321
322 [ WriteListR o depth stack_pointer  classes_p sizes_p i j k k2 l m n q senc mr;
323     if (depth > 0 && o == child(parent(o))) {
324         SortOutList(o);
325         o = child(parent(o));
326     }
327     for (::) {
328         if (o == 0) rfalse;
329         if (c_style & WORKFLAG_BIT && depth==0 && o hasnt workflag) {
330             o = sibling(o);
331             continue;
332         }
333         if (c_style & CONCEAL_BIT && (o has concealed || o has scenery)) {
334             o = sibling(o);
335             continue;
336         }
337         break;
338     }
339     classes_p = match_classes + stack_pointer;
340     sizes_p   = match_list + stack_pointer;
341
342     for (i=o,j=0 : i && (j+stack_pointer)<128 : i=NextEntry(i,depth),j++) {
343         classes_p->j = 0;
344         if (i.plural) k++;
345     }
346
347     if (c_style & ISARE_BIT) {
348         if (j == 1 && o hasnt pluralname) Tense(IS__TX, WAS__TX);
349         else                              Tense(ARE__TX, WERE__TX);
350         if (c_style & NEWLINE_BIT)   print ":^";
351         else                              print (char) ' ';
352         c_style = c_style - ISARE_BIT;
353     }
354
355     stack_pointer = stack_pointer+j+1;
356
357     if (k < 2) jump EconomyVersion;   ! It takes two to plural
358     n = 1;
359     for (i=o,k=0 : k<j : i=NextEntry(i,depth),k++)
360         if (classes_p->k == 0) {
361             classes_p->k = n; sizes_p->n = 1;
362             for (l=NextEntry(i,depth),m=k+1 : l && m<j : l=NextEntry(l,depth),m++)
363                 if (classes_p->m == 0 && i.plural && l.plural ~= 0) {
364                     if (ListEqual(i, l) == 1) {
365                         sizes_p->n = sizes_p->n + 1;
366                         classes_p->m = n;
367                     }
368                 }
369             n++;
370         }
371     n--;
372
373     for (i=1,j=o,k=0 : i<=n : i++,senc++) {
374         while (((classes_p->k) ~= i) && ((classes_p->k) ~= -i)) {
375             k++; j=NextEntry(j, depth);
376         }
377         m = sizes_p->i;
378         if (j == 0) mr = 0;
379         else {
380             if (j.list_together ~= 0 or lt_value && metaclass(j.list_together) == Routine or String &&
381                 j.list_together == mr) senc--;
382             mr = j.list_together;
383         }
384     }
385     senc--;
386
387     for (i=1,j=o,k=0,mr=0 : senc>=0 : i++,senc--) {
388         while (((classes_p->k) ~= i) && ((classes_p->k) ~= -i)) {
389             k++; j=NextEntry(j, depth);
390         }
391         if (j.list_together ~= 0 or lt_value) {
392             if (j.list_together == mr) {
393                 senc++;
394                 jump Omit_FL2;
395             }
396             k2 = NextEntry(j, depth);
397             if (k2 == 0 || k2.list_together ~= j.list_together) jump Omit_WL2;
398             k2 = metaclass(j.list_together);
399             if (k2 == Routine or String) {
400                 q = j; listing_size = 1; l = k; m = i;
401                 while (m < n && q.list_together == j.list_together) {
402                     m++;
403                     while (((classes_p->l) ~= m) && ((classes_p->l) ~= -m)) {
404                         l++; q = NextEntry(q, depth);
405                      }
406                     if (q.list_together == j.list_together) listing_size++;
407                 }
408                 ! print " [", listing_size, "] ";
409                 if (listing_size == 1) jump Omit_WL2;
410                 if (c_style & INDENT_BIT) Print__Spaces(2*(depth+wlf_indent));
411                 if (k2 == String) {
412                     q = 0;
413                     for (l=0 : l<listing_size : l++) q = q+sizes_p->(l+i);
414                     EnglishNumber(q); print " ";
415                     print (string) j.list_together;
416                     if (c_style & ENGLISH_BIT) print " (";
417                     if (c_style & INDENT_BIT)  print ":^";
418                 }
419                 q = c_style;
420                 if (k2 ~= String) {
421                     inventory_stage = 1;
422                     parser_one = j; parser_two = depth+wlf_indent;
423                     if (RunRoutines(j, list_together) == 1) jump Omit__Sublist2;
424                 }
425
426                 #Ifdef TARGET_ZCODE;
427                 @push lt_value;    @push listing_together;    @push listing_size;
428                 #Ifnot; ! TARGET_GLULX;
429                 @copy lt_value sp; @copy listing_together sp; @copy listing_size sp;
430                 #Endif; ! TARGET_;
431
432                 lt_value = j.list_together; listing_together = j; wlf_indent++;
433                 WriteListR(j, depth, stack_pointer); wlf_indent--;
434
435                 #Ifdef TARGET_ZCODE;
436                 @pull listing_size; @pull listing_together; @pull lt_value;
437                 #Ifnot; ! TARGET_GLULX;
438                 @copy sp listing_size;
439                 @copy sp listing_together;
440                 @copy sp lt_value;
441                 #Endif; ! TARGET_;
442
443                 if (k2 == String) {
444                     if (q & ENGLISH_BIT) print ")";
445                 }
446                 else {
447                     inventory_stage = 2;
448                     parser_one = j; parser_two = depth+wlf_indent;
449                     RunRoutines(j, list_together);
450                 }
451
452               .Omit__Sublist2;
453
454                 if (q & NEWLINE_BIT && c_style & NEWLINE_BIT == 0) new_line;
455                 c_style = q;
456                 mr = j.list_together;
457                 jump Omit_EL2;
458             }
459         }
460
461       .Omit_WL2;
462
463         if (WriteBeforeEntry(j, depth, 0, senc) == 1) jump Omit_FL2;
464         if (sizes_p->i == 1) {
465             if (c_style & NOARTICLE_BIT)  print (name) j;
466             else {
467                 if (c_style & DEFART_BIT) print (the) j;
468                 else                      print (a) j;
469             }
470             if (c_style & ID_BIT)         print " (", j, ")";
471         }
472         else {
473             if (c_style & DEFART_BIT) PrefaceByArticle(j, 1, sizes_p->i);
474             print (number) sizes_p->i, " ";
475             PrintOrRun(j, plural, 1);
476         }
477         if (sizes_p->i > 1 && j hasnt pluralname) {
478             give j pluralname;
479             WriteAfterEntry(j, depth, stack_pointer);
480             give j ~pluralname;
481         }
482         else {
483             WriteAfterEntry(j,depth,stack_pointer);
484         }
485       .Omit_EL2;
486
487         if (c_style & ENGLISH_BIT) {
488             if (senc == 1) print (SerialComma) i+senc, (string) AND__TX;
489             if (senc > 1)  print (string) COMMA__TX;
490         }
491      .Omit_FL2;
492     }
493     rtrue;
494
495   .EconomyVersion;
496
497     n = j;
498     for (i=1,j=o : i<=n : j=NextEntry(j,depth),i++,senc++) {
499         if (j.list_together ~= 0 or lt_value && metaclass(j.list_together) == Routine or String &&
500             j.list_together==mr) senc--;
501         mr = j.list_together;
502     }
503
504     for (i=1,j=o,mr=0 : i<=senc : j=NextEntry(j,depth),i++) {
505         if (j.list_together ~= 0 or lt_value) {
506             if (j.list_together == mr) {
507                 i--;
508                 jump Omit_FL;
509             }
510             k = NextEntry(j, depth);
511             if (k == 0 || k.list_together ~= j.list_together) jump Omit_WL;
512             k = metaclass(j.list_together);
513             if (k == Routine or String) {
514                 if (c_style & INDENT_BIT) Print__Spaces(2*(depth+wlf_indent));
515                 if (k == String) {
516                     q = j; l = 0;
517                     do {
518                         q = NextEntry(q, depth); l++;
519                     } until (q == 0 || q.list_together ~= j.list_together);
520                     EnglishNumber(l); print " ";
521                     print (string) j.list_together;
522                     if (c_style & ENGLISH_BIT) print " (";
523                     if (c_style & INDENT_BIT) print ":^";
524                 }
525                 q = c_style;
526                 if (k ~= String) {
527                     inventory_stage = 1;
528                     parser_one = j; parser_two = depth+wlf_indent;
529                     if (RunRoutines(j, list_together) == 1) jump Omit__Sublist;
530                 }
531
532                 #Ifdef TARGET_ZCODE;
533                 @push lt_value; @push listing_together; @push listing_size;
534                 #Ifnot; ! TARGET_GLULX;
535                 @copy lt_value sp; @copy listing_together sp; @copy listing_size sp;
536                 #Endif; ! TARGET_;
537
538                 lt_value = j.list_together; listing_together = j; wlf_indent++;
539                 WriteListR(j, depth, stack_pointer); wlf_indent--;
540
541                 #Ifdef TARGET_ZCODE;
542                 @pull listing_size; @pull listing_together; @pull lt_value;
543                 #Ifnot; ! TARGET_GLULX;
544                 @copy sp listing_size; @copy sp listing_together; @copy sp lt_value;
545                 #Endif; ! TARGET_;
546
547                 if (k == String) {
548                     if (q & ENGLISH_BIT) print ")";
549                 }
550                 else {
551                     inventory_stage = 2;
552                     parser_one = j; parser_two = depth+wlf_indent;
553                     RunRoutines(j, list_together);
554                 }
555
556               .Omit__Sublist;
557
558                 if (q & NEWLINE_BIT && c_style & NEWLINE_BIT == 0) new_line;
559                 c_style = q;
560                 mr = j.list_together;
561                 jump Omit_EL;
562             }
563         }
564
565       .Omit_WL;
566
567         if (WriteBeforeEntry(j, depth, i, senc) == 1) jump Omit_FL;
568         if (c_style & NOARTICLE_BIT)  print (name) j;
569         else {
570             if (c_style & DEFART_BIT) print (the) j;
571             else                      print (a) j;
572         }
573         if (c_style & ID_BIT)         print " (", j, ")";
574         WriteAfterEntry(j, depth, stack_pointer);
575
576       .Omit_EL;
577
578         if (c_style & ENGLISH_BIT) {
579             if (i == senc-1) print (SerialComma) senc, (string) AND__TX;
580             if (i < senc-1) print (string) COMMA__TX;
581         }
582
583   .Omit_FL;
584
585     }
586 ]; ! end of WriteListR
587
588 [ WriteBeforeEntry o depth ipos sentencepos
589     flag;
590
591     inventory_stage = 1;
592     if (c_style & INDENT_BIT) Print__Spaces(2*(depth+wlf_indent));
593     if (o.invent && (c_style & (PARTINV_BIT|FULLINV_BIT))) {
594         flag = PrintOrRun(o, invent, 1);
595         if (flag) {
596             if (c_style & ENGLISH_BIT) {
597                 if (ipos == sentencepos-1)
598                     print (SerialComma) sentencepos, (string) AND__TX;
599                 if (ipos < sentencepos-1)
600                     print (string) COMMA__TX;
601             }
602             if (c_style & NEWLINE_BIT) new_line;
603         }
604     }
605     return flag;
606 ];
607
608 [ WriteAfterEntry o depth stack_p
609     p recurse_flag parenth_flag eldest_child child_count combo i j;
610
611     inventory_stage = 2;
612     if (c_style & PARTINV_BIT) {
613         if (o.invent && RunRoutines(o, invent))
614             if (c_style & NEWLINE_BIT) ""; else rtrue;
615
616         combo = 0;
617         if (o has light && location hasnt light) combo=combo+1;
618         if (o has container && o hasnt open)     combo=combo+2;
619         if ((o has container && (o has open || o has transparent))) {
620             objectloop(i in o) {
621                 if (i hasnt concealed && i hasnt scenery) {
622                     j = true; break;
623                 }
624             }
625             if (~~j) combo=combo+4;
626         }
627         if (combo) L__M(##ListMiscellany, combo, o);
628     }   ! end of PARTINV_BIT processing
629
630     if (c_style & FULLINV_BIT) {
631         if (o.invent && RunRoutines(o, invent))
632             if (c_style & NEWLINE_BIT) ""; else rtrue;
633
634         if (o has light && o has worn) { L__M(##ListMiscellany, 8, o);  parenth_flag = true; }
635         else {
636             if (o has light)           { L__M(##ListMiscellany, 9, o);  parenth_flag = true; }
637             if (o has worn)            { L__M(##ListMiscellany, 10, o); parenth_flag = true; }
638         }
639
640         if (o has container)
641             if (o has openable) {
642                 if (parenth_flag) print (string) AND__TX;
643                 else              L__M(##ListMiscellany, 11, o);
644                 if (o has open)
645                     if (child(o)) L__M(##ListMiscellany, 12, o);
646                     else          L__M(##ListMiscellany, 13, o);
647                 else
648                     if (o has lockable && o has locked) L__M(##ListMiscellany, 15, o);
649                     else                                L__M(##ListMiscellany, 14, o);
650                 parenth_flag = true;
651             }
652             else
653                 if (child(o)==0 && o has transparent)
654                     if (parenth_flag) L__M(##ListMiscellany, 16, o);
655                     else              L__M(##ListMiscellany, 17, o);
656
657         if (parenth_flag) print ")";
658     }   ! end of FULLINV_BIT processing
659
660     if (c_style & CONCEAL_BIT) {
661         child_count = 0;
662         objectloop (p in o)
663             if (p hasnt concealed && p hasnt scenery) { child_count++; eldest_child = p; }
664     }
665     else { child_count = children(o); eldest_child = child(o); }
666
667     if (child_count && (c_style & ALWAYS_BIT)) {
668         if (c_style & ENGLISH_BIT) L__M(##ListMiscellany, 18, o);
669         recurse_flag = true;
670     }
671
672     if (child_count && (c_style & RECURSE_BIT)) {
673         if (o has supporter) {
674             if (c_style & ENGLISH_BIT) {
675                 if (c_style & TERSE_BIT) L__M(##ListMiscellany, 19, o);
676                 else                     L__M(##ListMiscellany, 20, o);
677                 if (o has animate)       print (string) WHOM__TX;
678                 else                     print (string) WHICH__TX;
679             }
680             recurse_flag = true;
681         }
682         if (o has container && (o has open || o has transparent)) {
683             if (c_style & ENGLISH_BIT) {
684                 if (c_style & TERSE_BIT) L__M(##ListMiscellany, 21, o);
685                 else                     L__M(##ListMiscellany, 22, o);
686                 if (o has animate)       print (string) WHOM__TX;
687                 else                     print (string) WHICH__TX;
688                 }
689             recurse_flag = true;
690         }
691     }
692
693     if (recurse_flag && (c_style & ENGLISH_BIT))
694         if (child_count > 1 || eldest_child has pluralname) Tense(ARE2__TX, WERE2__TX);
695         else                                                Tense(IS2__TX, WAS2__TX);
696
697     if (c_style & NEWLINE_BIT) new_line;
698
699     if (recurse_flag) {
700         o = child(o);
701         #Ifdef TARGET_ZCODE;
702         @push lt_value; @push listing_together; @push listing_size;
703         #Ifnot; ! TARGET_GLULX;
704         @copy lt_value sp; @copy listing_together sp; @copy listing_size sp;
705         #Endif;
706         lt_value = 0;   listing_together = 0;   listing_size = 0;
707         WriteListR(o, depth+1, stack_p);
708         #Ifdef TARGET_ZCODE;
709         @pull listing_size; @pull listing_together; @pull lt_value;
710         #Ifnot; ! TARGET_GLULX;
711         @copy sp listing_size; @copy sp listing_together; @copy sp lt_value;
712         #Endif;
713         if (c_style & TERSE_BIT) print ")";
714     }
715 ];
716
717 ! ----------------------------------------------------------------------------
718 ! LoopWithinObject(rtn,obj,arg)
719 !
720 ! rtn is the address of a user-supplied routine.
721 ! obj is an optional parent object whose dependents are to be processed; the
722 ! default is the current actor (normally the player).
723 ! arg is an optional argument passed to the rtn; this can be a single variable
724 ! or constant, or the address of an array (which enables multiple values to be
725 ! passed and returned).
726 !
727 ! For each object o which is a child, grandchild, great-grandchild, etc, of the
728 ! original obj, LoopWithinObject() calls rtn(o,arg).
729 !
730 ! The rtn should perform any appropriate testing or processing on each object o,
731 ! using the optional arg value if necessary. If the rtn returns true (or any
732 ! positive value), the children of o, if any, are also tested; those children
733 ! are skipped if rtn returns false. To terminate the loop before all objects
734 ! have been processed, rtn should return a large negative number (eg -99).
735 !
736 ! To deal with supporters and open containers, so that objects are processed
737 ! only if they are accessible to the player, rtn might end with these
738 ! statements:
739 !   if ((o has transparent or supporter) || (o has container && o has open)) rtrue;
740 !   rfalse;
741 ! or alternatively with:
742 !   c_style = RECURSE_BIT; return WillRecurs(o);
743 !
744 ! LoopWithinObject() returns the number of objects which have been processed.
745 ! ----------------------------------------------------------------------------
746
747 [ LoopWithinObject rtn obj arg
748     n o x y;
749     if (obj == 0) obj = actor;
750     o = child(obj);
751     while (o) {
752         y = parent(o); n++;
753         x = rtn(o, arg);    ! user-supplied routine returning x.
754                             ! if x < 0: skip up to next parent
755                             ! if x = 0: jump across to next sibling
756                             ! if x > 0: continue down to child objects
757         if (y ~= parent(o)) { RunTimeError(15, o); rfalse; }
758         if (x > 0 && child(o)) o = child(o);
759         else
760             while (o) {
761                 if (++x > 0 && sibling(o)) { o = sibling(o); break; }
762                 o = parent(o);
763                 if (o == obj) return n;
764             }
765     }
766 ];
767
768
769 ! ----------------------------------------------------------------------------
770 !  Much better menus can be created using one of the optional library
771 !  extensions.  These are provided for compatibility with previous practice:
772 ! ----------------------------------------------------------------------------
773
774 [ LowKey_Menu menu_choices EntryR ChoiceR lines main_title i j;
775     menu_nesting++;
776
777   .LKRD;
778
779     menu_item = 0;
780     lines = EntryR();
781     main_title = item_name;
782
783     print "--- "; print (string) main_title; print " ---^^";
784
785     if (menu_choices ofclass Routine) menu_choices();
786     else                              print (string) menu_choices;
787
788     for (::) {
789         L__M(##Miscellany, 52, lines);
790         print "> ";
791
792         #Ifdef TARGET_ZCODE;
793         #IfV3;
794         read buffer parse;
795         #Ifnot;
796         read buffer parse DrawStatusLine;
797         #Endif; ! V3
798         j = parse->1; ! number of words
799         #Ifnot; ! TARGET_GLULX;
800         KeyboardPrimitive(buffer, parse);
801         j = parse-->0; ! number of words
802         #Endif; ! TARGET_
803
804         i = parse-->1;
805         if (j == 0 || (i == QUIT1__WD or QUIT2__WD)) {
806             menu_nesting--; if (menu_nesting > 0) rfalse;
807             if (deadflag == 0) <<Look>>;
808             rfalse;
809         }
810         i = TryNumber(1);
811         if (i == 0) jump LKRD;
812         if (i < 1 || i > lines) continue;
813         menu_item = i;
814         j = ChoiceR();
815         if (j == 2) jump LKRD;
816         if (j == 3) rfalse;
817     }
818 ];
819
820 #Ifdef TARGET_ZCODE;
821
822 #IfV3;
823
824 [ DoMenu menu_choices EntryR ChoiceR; LowKey_Menu(menu_choices, EntryR, ChoiceR); ];
825
826 #Endif; ! V3
827
828 #IfV5;
829
830 [ DoMenu menu_choices EntryR ChoiceR
831          lines main_title main_wid cl i j oldcl pkey ch cw y x;
832     if (pretty_flag == 0) return LowKey_Menu(menu_choices, EntryR, ChoiceR);
833     menu_nesting++;
834     menu_item = 0;
835     lines = EntryR();
836     main_title = item_name; main_wid = item_width;
837     cl = 7;
838
839   .ReDisplay;
840
841     oldcl = 0;
842     @erase_window $ffff;
843     #Iftrue (#version_number == 6);
844     @set_cursor -1;
845     ch = HDR_FONTWUNITS->0;
846     #Ifnot;
847     ch = 1;
848     #Endif;
849     i = ch * (lines+7);
850     @split_window i;
851     i = HDR_SCREENWCHARS->0;
852     if (i == 0) i = 80;
853     @set_window 1;
854     @set_cursor 1 1;
855
856     #Iftrue (#version_number == 6);
857     @set_font 4 -> cw;
858     cw = HDR_FONTHUNITS->0;
859     #Ifnot;
860     cw = 1;
861     #Endif;
862
863     style reverse;
864     spaces(i); j=1+(i/2-main_wid)*cw;
865     @set_cursor 1 j;
866     print (string) main_title;
867     y=1+ch; @set_cursor y 1; spaces(i);
868     x=1+cw; @set_cursor y x; print (string) NKEY__TX;
869     j=1+(i-13)*cw; @set_cursor y j; print (string) PKEY__TX;
870     y=y+ch; @set_cursor y 1; spaces(i);
871     @set_cursor y x; print (string) RKEY__TX;
872     j=1+(i-18)*cw; @set_cursor y j;
873
874     if (menu_nesting == 1) print (string) QKEY1__TX;
875     else                   print (string) QKEY2__TX;
876     style roman;
877     y = y+2*ch;
878     @set_cursor y x; font off;
879
880     if (menu_choices ofclass String) print (string) menu_choices;
881     else                             menu_choices();
882
883     x = 1+3*cw;
884     for (::) {
885         if (cl ~= oldcl) {
886             if (oldcl>0) {
887                 y=1+(oldcl-1)*ch; @set_cursor y x; print " ";
888             }
889             y=1+(cl-1)*ch; @set_cursor y x; print ">";
890         }
891
892         oldcl = cl;
893         @read_char 1 -> pkey;
894         if (pkey == NKEY1__KY or NKEY2__KY or 130) {
895             cl++; if (cl == 7+lines) cl = 7; continue;
896         }
897         if (pkey == PKEY1__KY or PKEY2__KY or 129) {
898             cl--; if (cl == 6) cl = 6+lines; continue;
899         }
900         if (pkey == QKEY1__KY or QKEY2__KY or 27 or 131) break;
901         if (pkey == 10 or 13 or 132) {
902             @set_window 0; font on;
903             new_line; new_line; new_line;
904
905             menu_item = cl-6;
906             EntryR();
907
908             @erase_window $ffff;
909             @split_window ch;
910             i = HDR_SCREENWCHARS->0; if ( i== 0) i = 80;
911             @set_window 1; @set_cursor 1 1; style reverse; spaces(i);
912             j=1+(i/2-item_width)*cw;
913             @set_cursor 1 j;
914             print (string) item_name;
915             style roman; @set_window 0; new_line;
916
917             i = ChoiceR();
918             if (i == 2) jump ReDisplay;
919             if (i == 3) break;
920
921             L__M(##Miscellany, 53);
922             @read_char 1 -> pkey; jump ReDisplay;
923         }
924     }
925
926     menu_nesting--; if (menu_nesting > 0) rfalse;
927     font on; @set_cursor 1 1;
928     @erase_window $ffff; @set_window 0;
929     #Iftrue (#version_number == 6);
930     @set_cursor -2;
931     #Endif;
932     new_line; new_line; new_line;
933     if (deadflag == 0) <<Look>>;
934 ];
935
936 #Endif; ! V5
937
938 #Ifnot; ! TARGET_GLULX
939
940 [ DoMenu menu_choices EntryR ChoiceR
941     winwid winhgt lines main_title main_wid cl i oldcl pkey;
942
943     if (pretty_flag == 0 || gg_statuswin == 0) return LowKey_Menu(menu_choices, EntryR, ChoiceR);
944
945     menu_nesting++;
946     menu_item = 0;
947     lines = EntryR();
948     main_title = item_name;
949     main_wid = item_width;
950
951     cl = 0;
952
953     ! If we printed "hit arrow keys" here, it would be appropriate to
954     ! check for the availability of Glk input keys. But we actually
955     ! print "hit N/P/Q". So it's reasonable to silently accept Glk
956     ! arrow key codes as secondary options.
957
958   .ReDisplay;
959
960     glk_window_clear(gg_statuswin);
961     glk_window_clear(gg_mainwin);
962     glk_set_window(gg_statuswin);
963     StatusLineHeight(lines+7);
964     glk_window_get_size(gg_statuswin, gg_arguments, gg_arguments+4);
965     winwid = gg_arguments-->0;
966     winhgt = gg_arguments-->1;
967     glk_set_style(style_Subheader);
968     glk_window_move_cursor(gg_statuswin, winwid/2-main_wid, 0);
969     print (string) main_title;
970     glk_window_move_cursor(gg_statuswin, 1, 1);
971     print (string) NKEY__TX;
972     glk_window_move_cursor(gg_statuswin, winwid-13, 1);
973     print (string) PKEY__TX;
974     glk_window_move_cursor(gg_statuswin, 1, 2);
975     print (string) RKEY__TX;
976     glk_window_move_cursor(gg_statuswin, winwid-18, 2);
977     if (menu_nesting == 1) print (string) QKEY1__TX;
978     else                   print (string) QKEY2__TX;
979     glk_set_style(style_Normal);
980     glk_window_move_cursor(gg_statuswin, 1, 4);
981     if (menu_choices ofclass String) print (string) menu_choices;
982     else                             menu_choices();
983
984     oldcl = -1;
985
986     for (::) {
987         if (cl ~= oldcl) {
988             if (cl < 0 || cl >= lines) cl = 0;
989             if (oldcl >= 0) {
990                 glk_window_move_cursor(gg_statuswin, 3, oldcl+6);
991                 print (char) ' ';
992             }
993             oldcl = cl;
994             glk_window_move_cursor(gg_statuswin, 3, oldcl+6);
995             print (char) '>';
996         }
997         pkey = KeyCharPrimitive(gg_statuswin, true);
998         if (pkey == $80000000) jump ReDisplay;
999         if (pkey == NKEY1__KY or NKEY2__KY or $fffffffb) {
1000             cl++;
1001             if (cl >= lines) cl = 0;
1002             continue;
1003         }
1004         if (pkey == PKEY1__KY or PKEY2__KY or $fffffffc) {
1005             cl--;
1006             if (cl < 0) cl = lines-1;
1007             continue;
1008         }
1009         if (pkey == QKEY1__KY or QKEY2__KY or $fffffff8 or $fffffffe) break;
1010         if (pkey == $fffffffa or $fffffffd) {
1011             glk_set_window(gg_mainwin);
1012             new_line; new_line; new_line;
1013             menu_item = cl+1;
1014             EntryR();
1015             glk_window_clear(gg_statuswin);
1016             glk_window_clear(gg_mainwin);
1017             glk_set_window(gg_statuswin);
1018             StatusLineHeight(1);
1019             glk_window_get_size(gg_statuswin, gg_arguments, gg_arguments+4);
1020             winwid = gg_arguments-->0;
1021             winhgt = gg_arguments-->1;
1022             glk_set_style(style_Subheader);
1023             glk_window_move_cursor(gg_statuswin, winwid/2-item_width, 0);
1024             print (string) item_name;
1025             glk_set_style(style_Normal);
1026             glk_set_window(gg_mainwin);
1027             new_line;
1028             i = ChoiceR();
1029             if (i == 2) jump ReDisplay;
1030             if (i == 3) break;
1031             L__M(##Miscellany, 53);
1032             pkey = KeyCharPrimitive(gg_mainwin, 1);
1033             jump ReDisplay;
1034         }
1035     }
1036
1037     ! done with this menu...
1038     menu_nesting--;
1039     if (menu_nesting > 0) rfalse;
1040     glk_set_window(gg_mainwin);
1041     glk_window_clear(gg_mainwin);
1042     new_line; new_line; new_line;
1043     if (deadflag == 0) <<Look>>;
1044 ];
1045
1046 #Endif; ! TARGET_
1047
1048 ! ----------------------------------------------------------------------------
1049 !   A cunning routine (which could have been a daemon, but isn't, for the
1050 !   sake of efficiency) to move objects which could be in many rooms about
1051 !   so that the player never catches one not in place
1052 ! ----------------------------------------------------------------------------
1053
1054 [ MoveFloatingObjects i k l m address flag;
1055     if (location == player or nothing) return;
1056     objectloop (i) {
1057         address = i.&found_in;
1058         if (address && i hasnt non_floating && ~~IndirectlyContains(player, i)) {
1059             if (metaclass(address-->0) == Routine)
1060                 flag = i.found_in();
1061             else {
1062                 flag = false;
1063                 k = i.#found_in/WORDSIZE;
1064                 for (l=0 : l<k : l++) {
1065                     m = address-->l;
1066                     if ((m in Class && location ofclass m) ||
1067                             m == location || m in location) {
1068                         flag = true;
1069                         break;
1070                     }
1071                 }
1072             }
1073             if (flag) {
1074                 if (i notin location) move i to location;
1075             } else {
1076                 if (parent(i)) remove i;
1077             }
1078         }
1079     }
1080 ];
1081
1082 ! ----------------------------------------------------------------------------
1083 !   Two little routines for moving the player safely.
1084 ! ----------------------------------------------------------------------------
1085
1086 [ PlayerTo newplace flag;
1087     NoteDeparture();
1088     move player to newplace;
1089     while (parent(newplace)) newplace = parent(newplace);
1090     location = real_location = newplace;
1091     MoveFloatingObjects(); AdjustLight(1);
1092     switch (flag) {
1093       0:    <Look>;
1094       1:    NoteArrival(); ScoreArrival();
1095       2:    LookSub(1);
1096     }
1097 ];
1098
1099 [ MovePlayer direc; <Go direc>; <Look>; ];
1100
1101 ! ----------------------------------------------------------------------------
1102 !   The handy YesOrNo routine, and some "meta" verbs
1103 ! ----------------------------------------------------------------------------
1104
1105 [ YesOrNo noStatusRedraw
1106     i j;
1107     for (::) {
1108         #Ifdef TARGET_ZCODE;
1109         if (location == nothing || parent(player) == nothing || noStatusRedraw)
1110             read buffer parse;
1111         else read buffer parse DrawStatusLine;
1112         j = parse->1;
1113         #Ifnot; ! TARGET_GLULX;
1114         noStatusRedraw = 0; ! suppress warning
1115         KeyboardPrimitive(buffer, parse);
1116         j = parse-->0;
1117         #Endif; ! TARGET_
1118         if (j) { ! at least one word entered
1119             i = parse-->1;
1120             if (i == YES1__WD or YES2__WD or YES3__WD) rtrue;
1121             if (i == NO1__WD  or NO2__WD  or NO3__WD) rfalse;
1122         }
1123         L__M(##Quit, 1); print "> ";
1124     }
1125 ];
1126
1127 #Ifdef TARGET_ZCODE;
1128
1129 [ QuitSub;
1130     L__M(##Quit, 2);
1131     if (YesOrNo()) quit;
1132 ];
1133
1134 [ RestartSub;
1135     L__M(##Restart, 1);
1136     if (YesOrNo()) { @restart; L__M(##Restart, 2); }
1137 ];
1138
1139 [ RestoreSub;
1140     restore Rmaybe;
1141     return L__M(##Restore, 1);
1142   .RMaybe;
1143     L__M(##Restore, 2);
1144 ];
1145
1146 [ SaveSub flag;
1147     #IfV5;
1148     @save -> flag;
1149     switch (flag) {
1150       0: L__M(##Save, 1);
1151       1: L__M(##Save, 2);
1152       2:
1153         RestoreColours();
1154         L__M(##Restore, 2);
1155     }
1156     #Ifnot;
1157     save Smaybe;
1158     return L__M(##Save, 1);
1159   .SMaybe;
1160     L__M(##Save, 2);
1161     #Endif; ! V5
1162 ];
1163
1164 [ VerifySub;
1165     @verify ?Vmaybe;
1166     jump Vwrong;
1167   .Vmaybe;
1168     return L__M(##Verify, 1);
1169   .Vwrong;
1170     L__M(##Verify, 2);
1171 ];
1172
1173 [ ScriptOnSub;
1174     transcript_mode = ((HDR_GAMEFLAGS-->0) & 1);
1175     if (transcript_mode) return L__M(##ScriptOn, 1);
1176     @output_stream 2;
1177     if (((HDR_GAMEFLAGS-->0) & 1) == 0) return L__M(##ScriptOn, 3);
1178     L__M(##ScriptOn, 2);
1179     transcript_mode = true;
1180 ];
1181
1182 [ ScriptOffSub;
1183     transcript_mode = ((HDR_GAMEFLAGS-->0) & 1);
1184     if (transcript_mode == false) return L__M(##ScriptOff, 1);
1185     L__M(##ScriptOff, 2);
1186     @output_stream -2;
1187     if ((HDR_GAMEFLAGS-->0) & 1) return L__M(##ScriptOff, 3);
1188     transcript_mode = false;
1189 ];
1190
1191 [ CommandsOnSub;
1192     @output_stream 4;
1193     xcommsdir = 1;
1194     L__M(##CommandsOn, 1);
1195 ];
1196
1197 [ CommandsOffSub;
1198     if (xcommsdir == 1) @output_stream -4;
1199     xcommsdir = 0;
1200     L__M(##CommandsOff, 1);
1201 ];
1202
1203 [ CommandsReadSub;
1204     @input_stream 1;
1205     xcommsdir = 2;
1206     L__M(##CommandsRead, 1);
1207 ];
1208
1209 #Ifnot; ! TARGET_GLULX;
1210
1211 [ QuitSub;
1212     L__M(##Quit, 2);
1213     if (YesOrNo()) quit;
1214 ];
1215
1216 [ RestartSub;
1217     L__M(##Restart,1);
1218     if (YesOrNo()) { @restart; L__M(##Restart, 2); }
1219 ];
1220
1221 [ RestoreSub res fref;
1222     fref = glk_fileref_create_by_prompt($01, $02, 0);
1223     if (fref == 0) jump RFailed;
1224     gg_savestr = glk_stream_open_file(fref, $02, GG_SAVESTR_ROCK);
1225     glk_fileref_destroy(fref);
1226     if (gg_savestr == 0) jump RFailed;
1227     @restore gg_savestr res;
1228     glk_stream_close(gg_savestr, 0);
1229     gg_savestr = 0;
1230   .RFailed;
1231     L__M(##Restore, 1);
1232 ];
1233
1234 [ SaveSub res fref;
1235     fref = glk_fileref_create_by_prompt($01, $01, 0);
1236     if (fref == 0) jump SFailed;
1237     gg_savestr = glk_stream_open_file(fref, $01, GG_SAVESTR_ROCK);
1238     glk_fileref_destroy(fref);
1239     if (gg_savestr == 0) jump SFailed;
1240     @save gg_savestr res;
1241     if (res == -1) {
1242         ! The player actually just typed "restore". We're going to print
1243         !  L__M(##Restore,2); the Z-Code Inform library does this correctly
1244         ! now. But first, we have to recover all the Glk objects; the values
1245         ! in our global variables are all wrong.
1246         GGRecoverObjects();
1247         glk_stream_close(gg_savestr, 0);
1248         gg_savestr = 0;
1249         return L__M(##Restore, 2);
1250     }
1251     glk_stream_close(gg_savestr, 0);
1252     gg_savestr = 0;
1253     if (res == 0) return L__M(##Save, 2);
1254   .SFailed;
1255     L__M(##Save, 1);
1256 ];
1257
1258 [ VerifySub res;
1259     @verify res;
1260     if (res == 0) return L__M(##Verify, 1);
1261     L__M(##Verify, 2);
1262 ];
1263
1264 [ ScriptOnSub;
1265     if (gg_scriptstr) return L__M(##ScriptOn, 1);
1266     if (gg_scriptfref == 0) {
1267         gg_scriptfref = glk_fileref_create_by_prompt($102, $05, GG_SCRIPTFREF_ROCK);
1268         if (gg_scriptfref == 0) jump S1Failed;
1269     }
1270     gg_scriptstr = glk_stream_open_file(gg_scriptfref, $05, GG_SCRIPTSTR_ROCK);
1271     if (gg_scriptstr == 0) jump S1Failed;
1272     glk_window_set_echo_stream(gg_mainwin, gg_scriptstr);
1273     L__M(##ScriptOn, 2);
1274     VersionSub();
1275     return;
1276   .S1Failed;
1277     L__M(##ScriptOn, 3);
1278 ];
1279
1280 [ ScriptOffSub;
1281     if (gg_scriptstr == 0) return L__M(##ScriptOff,1);
1282     L__M(##ScriptOff, 2);
1283     glk_stream_close(gg_scriptstr, 0);
1284     gg_scriptstr = 0;
1285 ];
1286
1287 [ CommandsOnSub fref;
1288     if (gg_commandstr) {
1289         if (gg_command_reading) return L__M(##CommandsOn, 2);
1290         else                    return L__M(##CommandsOn, 3);
1291     }
1292     fref = glk_fileref_create_by_prompt($103, $01, 0);
1293     if (fref == 0) return L__M(##CommandsOn, 4);
1294     gg_command_reading = false;
1295     gg_commandstr = glk_stream_open_file(fref, $01, GG_COMMANDWSTR_ROCK);
1296     glk_fileref_destroy(fref);
1297     if (gg_commandstr == 0) return L__M(##CommandsOn, 4);
1298     L__M(##CommandsOn, 1);
1299 ];
1300
1301 [ CommandsOffSub;
1302     if (gg_commandstr == 0) return L__M(##CommandsOff, 2);
1303     if (gg_command_reading) return L__M(##CommandsRead, 5);
1304     glk_stream_close(gg_commandstr, 0);
1305     gg_commandstr = 0;
1306     gg_command_reading = false;
1307     L__M(##CommandsOff, 1);
1308 ];
1309
1310 [ CommandsReadSub fref;
1311     if (gg_commandstr) {
1312         if (gg_command_reading) return L__M(##CommandsRead, 2);
1313         else                    return L__M(##CommandsRead, 3);
1314     }
1315     fref = glk_fileref_create_by_prompt($103, $02, 0);
1316     if (fref == 0) return L__M(##CommandsRead, 4);
1317     gg_command_reading = true;
1318     gg_commandstr = glk_stream_open_file(fref, $02, GG_COMMANDRSTR_ROCK);
1319     glk_fileref_destroy(fref);
1320     if (gg_commandstr == 0) return L__M(##CommandsRead, 4);
1321     L__M(##CommandsRead, 1);
1322 ];
1323
1324 #Endif; ! TARGET_;
1325
1326 [ NotifyOnSub;  notify_mode = true; L__M(##NotifyOn);  ];
1327 [ NotifyOffSub; notify_mode = false; L__M(##NotifyOff); ];
1328
1329 [ Places1Sub i j k;
1330     L__M(##Places, 1);
1331     objectloop (i has visited) j++;
1332     objectloop (i has visited) {
1333         print (name) i; k++;
1334         if (k == j) return L__M(##Places, 2);
1335         if (k == j-1) print (SerialComma) j, (string) AND__TX;
1336         else          print (string) COMMA__TX;
1337     }
1338 ];
1339
1340 [ Objects1Sub i j f;
1341     L__M(##Objects, 1);
1342     objectloop (i has moved) {
1343        f = 1; print (the) i; j = parent(i);
1344         if (j) {
1345            if (j == player) {
1346                if (i has worn) L__M(##Objects, 3, j, i);
1347                else            L__M(##Objects, 4, j, i);
1348                 jump Obj__Ptd;
1349             }
1350             if (j has animate)   { L__M(##Objects, 5, j, i); jump Obj__Ptd; }
1351             if (j has visited)   { L__M(##Objects, 6, j, i); jump Obj__Ptd; }
1352             if (j has container) { L__M(##Objects, 8, j, i); jump Obj__Ptd; }
1353             if (j has supporter) { L__M(##Objects, 9, j, i); jump Obj__Ptd; }
1354             if (j has enterable) { L__M(##Objects, 7, j, i); jump Obj__Ptd; }
1355         }
1356         L__M(##Objects, 10, j, i);
1357
1358       .Obj__Ptd;
1359
1360         new_line;
1361     }
1362     if (f == 0) L__M(##Objects, 2);
1363 ];
1364
1365 ! ----------------------------------------------------------------------------
1366 !   The scoring system
1367 ! ----------------------------------------------------------------------------
1368
1369 [ ScoreSub;
1370     #Ifdef NO_SCORE;
1371     if (deadflag == 0) L__M(##Score, 2);
1372     #Ifnot;
1373     if (deadflag) new_line;
1374     L__M(##Score, 1);
1375     if(PrintRank() == false) LibraryExtensions.RunAll(ext_printrank);
1376     #Endif; ! NO_SCORE
1377 ];
1378
1379 #Ifndef TaskScore;
1380 [ TaskScore i;
1381     return task_scores->i;
1382 ];
1383 #Endif;
1384
1385 [ Achieved num;
1386     if (task_done->num == 0) {
1387         task_done->num = 1;
1388         score = score + TaskScore(num);
1389     }
1390 ];
1391
1392 [ PANum m n;
1393     print "  ";
1394     n = m;
1395     if (n < 0)    { n = -m; n = n*10; }
1396     if (n < 10)   { print "   "; jump Panuml; }
1397     if (n < 100)  { print "  "; jump Panuml; }
1398     if (n < 1000) { print " "; }
1399
1400   .Panuml;
1401
1402     print m, " ";
1403 ];
1404
1405 [ FullScoreSub i;
1406     ScoreSub();
1407     if (score == 0 || TASKS_PROVIDED == 1) rfalse;
1408     new_line;
1409     L__M(##FullScore, 1);
1410     for (i=0 : i<NUMBER_TASKS : i++)
1411         if (task_done->i == 1) {
1412             PANum(TaskScore(i));
1413             if(PrintTaskName(i) == false)
1414                 LibraryExtensions.RunAll(ext_printtaskname,i);
1415         }
1416     if (things_score) {
1417         PANum(things_score);
1418         L__M(##FullScore, 2);
1419     }
1420     if (places_score) {
1421         PANum(places_score);
1422         L__M(##FullScore, 3);
1423     }
1424     new_line; PANum(score); L__M(##FullScore, 4);
1425 ];
1426
1427 ! ----------------------------------------------------------------------------
1428 !   Real verbs start here: Inventory
1429 ! ----------------------------------------------------------------------------
1430
1431 [ InvWideSub;
1432     if (actor == player)
1433         inventory_style = ENGLISH_BIT+FULLINV_BIT+RECURSE_BIT;
1434     else
1435         inventory_style = ENGLISH_BIT+PARTINV_BIT;
1436     <Inv, actor>;
1437     inventory_style = 0;
1438 ];
1439
1440 [ InvTallSub;
1441     if (actor == player)
1442         inventory_style = NEWLINE_BIT+INDENT_BIT+FULLINV_BIT+RECURSE_BIT;
1443     else
1444         inventory_style = NEWLINE_BIT+INDENT_BIT+PARTINV_BIT;
1445     <Inv, actor>;
1446     inventory_style = 0;
1447 ];
1448
1449 [ InvSub x;
1450     if (child(actor) == 0)   return L__M(##Inv, 1);
1451     if (inventory_style == 0)
1452         if (actor == player) return InvTallSub();
1453         else                 return InvWideSub();
1454     L__M(##Inv, 2);
1455     if (inventory_style & NEWLINE_BIT) L__M(##Inv, 3); else print " ";
1456
1457     WriteListFrom(child(actor), inventory_style, 1);
1458     if (inventory_style & ENGLISH_BIT) L__M(##Inv, 4);
1459
1460     #Ifndef MANUAL_PRONOUNS;
1461     objectloop (x in player) PronounNotice(x);
1462     #Endif;
1463     x = 0; ! To prevent a "not used" error
1464     AfterRoutines();
1465 ];
1466
1467 ! ----------------------------------------------------------------------------
1468 !   The object tree and determining the possibility of moves
1469 ! ----------------------------------------------------------------------------
1470
1471 [ CommonAncestor o1 o2 i j;
1472     ! Find the nearest object indirectly containing o1 and o2,
1473     ! or return 0 if there is no common ancestor.
1474     i = o1;
1475     while (i) {
1476         j = o2;
1477         while (j) {
1478             if (j == i) return i;
1479             j = parent(j);
1480         }
1481         i = parent(i);
1482     }
1483     return 0;
1484 ];
1485
1486 [ IndirectlyContains o1 o2;
1487     ! Does o1 indirectly contain o2?  (Same as testing if their common ancestor is o1.)
1488     while (o2) {
1489         if (o1 == o2) rtrue;
1490         if (o2 ofclass Class) rfalse;
1491         o2 = parent(o2);
1492     }
1493     rfalse;
1494 ];
1495
1496 [ ObjectScopedBySomething item i j k l m;
1497     i = item;
1498     objectloop (j .& add_to_scope) {
1499         l = j.&add_to_scope;
1500         k = (j.#add_to_scope)/WORDSIZE;
1501         if (l-->0 ofclass Routine) continue;
1502         for (m=0 : m<k : m++)
1503             if (l-->m == i) return j;
1504     }
1505     rfalse;
1506 ];
1507
1508 [ ObjectIsUntouchable item flag1 flag2 ancestor i;
1509     ! Determine if there's any barrier preventing the actor from moving
1510     ! things to "item".  Return false if no barrier; otherwise print a
1511     ! suitable message and return true.
1512     ! If flag1 is set, do not print any message.
1513     ! If flag2 is set, also apply Take/Remove restrictions.
1514
1515     ! If the item has been added to scope by something, it's first necessary
1516     ! for that something to be touchable.
1517
1518     ancestor = CommonAncestor(actor, item);
1519     if (ancestor == 0) {
1520         ancestor = item;
1521         while (ancestor && (i = ObjectScopedBySomething(ancestor)) == 0)
1522             ancestor = parent(ancestor);
1523         if (i) {
1524             if (ObjectIsUntouchable(i, flag1, flag2)) return;
1525             ! An item immediately added to scope
1526         }
1527     }
1528     else
1529
1530     ! First, a barrier between the actor and the ancestor.  The actor
1531     ! can only be in a sequence of enterable objects, and only closed
1532     ! containers form a barrier.
1533
1534     if (actor ~= ancestor) {
1535         i = parent(actor);
1536         while (i ~= ancestor) {
1537             if (i has container && i hasnt open) {
1538                 if (flag1) rtrue;
1539                 return L__M(##Take, 9, i, noun);
1540             }
1541             i = parent(i);
1542         }
1543     }
1544
1545     ! Second, a barrier between the item and the ancestor.  The item can
1546     ! be carried by someone, part of a piece of machinery, in or on top
1547     ! of something and so on.
1548
1549     i = parent(item);
1550     if (item ~= ancestor && i ~= player) {
1551         while (i ~= ancestor) {
1552             if (flag2 && i hasnt container && i hasnt supporter) {
1553                 if (i has animate) {
1554                     if (flag1) rtrue;
1555                     return L__M(##Take, 6, i, noun);
1556                 }
1557                 if (i has transparent) {
1558                     if (flag1) rtrue;
1559                     return L__M(##Take, 7, i, noun);
1560                 }
1561                 if (flag1) rtrue;
1562                 return L__M(##Take, 8, item, noun);
1563             }
1564             if (i has container && i hasnt open) {
1565                 if (flag1) rtrue;
1566                 return L__M(##Take, 9, i, noun);
1567             }
1568             i = parent(i);
1569         }
1570     }
1571     rfalse;
1572 ];
1573
1574 [ AttemptToTakeObject item
1575     ancestor after_recipient i k;
1576     ! Try to transfer the given item to the actor: return false
1577     ! if successful, true if unsuccessful, printing a suitable message
1578     ! in the latter case.
1579     ! People cannot ordinarily be taken.
1580     if (item == actor) return L__M(##Take, 2, noun);
1581     if (item has animate) return L__M(##Take, 3, item);
1582
1583     ancestor = CommonAncestor(actor, item);
1584
1585     if (ancestor == 0) {
1586         i = ObjectScopedBySomething(item);
1587         if (i) ancestor = CommonAncestor(actor, i);
1588     }
1589
1590     ! Is the actor indirectly inside the item?
1591     if (ancestor == item) return L__M(##Take, 4, item);
1592
1593     ! Does the actor already directly contain the item?
1594     if (item in actor) return L__M(##Take, 5, item);
1595
1596     ! Can the actor touch the item, or is there (e.g.) a closed container
1597     ! in the way?
1598     if (ObjectIsUntouchable(item, false, true)) rtrue;
1599
1600     ! The item is now known to be accessible.
1601
1602     ! Consult the immediate possessor of the item, if it's in a container
1603     ! which the actor is not in.
1604
1605     i = parent(item);
1606     if (i && i ~= ancestor && (i has container or supporter)) {
1607         after_recipient = i;
1608         k = action; action = ##LetGo;
1609         if (RunRoutines(i, before)) { action = k; rtrue; }
1610         action = k;
1611     }
1612
1613     if (item has scenery) return L__M(##Take, 10, item);
1614     if (item has static)  return L__M(##Take, 11, item);
1615
1616     ! The item is now known to be available for taking.  Is the player
1617     ! carrying too much?  If so, possibly juggle items into the rucksack
1618     ! to make room.
1619
1620     if (ObjectDoesNotFit(item, actor) ||
1621         LibraryExtensions.RunWhile(ext_objectdoesnotfit, false, item, actor)) return;
1622     if (AtFullCapacity(item, actor)) return L__M(##Take, 12, item);
1623
1624     ! Transfer the item.
1625
1626     move item to actor; give item ~worn;
1627
1628     ! Send "after" message to the object letting go of the item, if any.
1629
1630     if (after_recipient) {
1631         k = action; action = ##LetGo;
1632         if (RunRoutines(after_recipient, after)) { action = k; rtrue; }
1633         action = k;
1634     }
1635     rfalse;
1636 ];
1637
1638 [ AtFullCapacity n s
1639     obj k;
1640     n = n; ! suppress compiler warning
1641     if (s == actor) {
1642         objectloop (obj in s)
1643             if (obj hasnt worn) k++;
1644     } else
1645         k = children(s);
1646
1647     if (k < RunRoutines(s, capacity) || (s == player && RoomInSack())) rfalse;
1648 ];
1649
1650 [ RoomInSack
1651     obj ks;
1652     if (SACK_OBJECT && SACK_OBJECT in player) {
1653         ks = keep_silent; keep_silent = 2;
1654         for (obj=youngest(player) : obj : obj=elder(obj))
1655             if (obj ~= SACK_OBJECT && obj hasnt worn or light) {
1656                 <Insert obj SACK_OBJECT>;
1657                 if (obj in SACK_OBJECT) {
1658                     keep_silent = ks;
1659                     return L__M(##Take, 13, obj, SACK_OBJECT);
1660                 }
1661             }
1662         keep_silent = ks;
1663     }
1664     rfalse;
1665 ];
1666
1667 ! ----------------------------------------------------------------------------
1668 !   Support for implicit actions
1669 ! ----------------------------------------------------------------------------
1670
1671 [ CheckImplicitAction act o1 o2
1672     sav_act sav_noun sav_sec res;
1673     if (o1 provides before_implicit) {
1674         sav_act  = action; action = act;
1675         sav_noun = noun;   noun   = o1;
1676         if (o2) { sav_sec  = second; second = o2; }
1677         res = RunRoutines(o1, before_implicit);
1678         action = sav_act; noun = sav_noun;
1679         if (sav_sec) second = sav_sec;
1680     }
1681     else {
1682         if (no_implicit_actions)
1683             res = 2;
1684         else
1685             res = 0;
1686     }
1687     return res;
1688 ];
1689
1690 [ ImplicitTake obj
1691     res ks supcon;
1692     switch (metaclass(obj)) { Class, String, Routine, nothing: rfalse; }
1693     if (obj in actor) rfalse;
1694     if (action_to_be == ##Drop && ~~IndirectlyContains(actor, obj)) rfalse;
1695     res = CheckImplicitAction(##Take, obj);
1696     ! 0 = Take object, Tell the user (normal default)
1697     ! 1 = Take object, don't Tell
1698     ! 2 = don't Take object  continue       (default with no_implicit_actions)
1699     ! 3 = don't Take object, don't continue
1700     if (res >= 2) rtrue;
1701     if (parent(obj) && parent(obj) has container or supporter) supcon = parent(obj);
1702     ks = keep_silent; keep_silent = 2; AttemptToTakeObject(obj); keep_silent = ks;
1703     if (obj notin actor) rtrue;
1704     if (res == 0 && ~~keep_silent)
1705         if (supcon) L__M(##Miscellany, 58, obj, supcon);
1706         else        L__M(##Miscellany, 26, obj);
1707     rfalse;
1708 ];
1709
1710 [ ImplicitExit obj
1711     res ks;
1712     if (parent(obj) == nothing) rfalse;
1713     res = CheckImplicitAction(##Exit, obj);
1714     ! 0 = Exit object, Tell the user (normal default)
1715     ! 1 = Exit object, don't Tell
1716     ! 2 = don't Exit object  continue       (default with no_implicit_actions)
1717     ! 3 = don't Exit object, don't continue
1718     if (res >= 2) rtrue;
1719     ks = keep_silent; keep_silent = 2; <Exit obj, actor>; keep_silent = ks;
1720     if (parent(actor) == obj) rtrue;
1721     if (res == 0 && ~~keep_silent) L__M(##Exit, 5, obj);
1722     rfalse;
1723 ];
1724
1725 [ ImplicitClose obj
1726     res ks;
1727     if (obj hasnt open) rfalse;
1728     res = CheckImplicitAction(##Close, obj);
1729     ! 0 = Close object, Tell the user (normal default)
1730     ! 1 = Close object, don't Tell
1731     ! 2 = don't Close object  continue       (default with no_implicit_actions)
1732     ! 3 = don't Close object, don't continue
1733     if (res >= 2) rtrue;
1734     ks = keep_silent; keep_silent = 2; <Close obj, actor>; keep_silent = ks;
1735     if (obj has open) rtrue;
1736     if (res == 0 && ~~keep_silent) L__M(##Close, 4, obj);
1737     rfalse;
1738 ];
1739
1740 [ ImplicitOpen obj
1741     res temp inp1temp;
1742     if (obj has open) rfalse;
1743     res = CheckImplicitAction(##Open, obj);
1744     ! 0 = Open object, Tell the user (normal default)
1745     ! 1 = Open object, don't Tell
1746     ! 2 = don't Open object  continue       (default with no_implicit_actions)
1747     ! 3 = don't Open object, don't continue
1748     if (res >= 2) rtrue;
1749     if (obj has locked) rtrue;
1750     temp = keep_silent; keep_silent = 2; <Open obj, actor>; keep_silent = temp;
1751     if (obj hasnt open) rtrue;
1752     if (res == 0 && ~~keep_silent) L__M(##Open, 6, obj);
1753     temp = action; action = ##Open;
1754     inp1temp = inp1; inp1 = obj;
1755     AfterRoutines();
1756     inp1 = inp1temp; action = temp;
1757     rfalse;
1758 ];
1759
1760 [ ImplicitUnlock obj;
1761     if (obj has locked) rtrue;
1762     rfalse;
1763 ];
1764
1765 [ ImplicitDisrobe obj
1766     res ks;
1767     if (obj hasnt worn) rfalse;
1768     res = CheckImplicitAction(##Disrobe, obj);
1769     ! 0 = Take off object, Tell the user (normal default)
1770     ! 1 = Take off object, don't Tell
1771     ! 2 = don't Take off object  continue       (default with no_implicit_actions)
1772     ! 3 = don't Take off object, don't continue
1773     if (res >= 2) rtrue;
1774     ks = keep_silent; keep_silent = 1; <Disrobe obj, actor>; keep_silent = ks;
1775     if (obj has worn && obj in actor) rtrue;
1776     if (res == 0 && ~~keep_silent) L__M(##Drop, 3, obj);
1777     rfalse;
1778 ];
1779
1780
1781 ! ----------------------------------------------------------------------------
1782 !   Object movement verbs
1783 ! ----------------------------------------------------------------------------
1784
1785 [ TakeSub;
1786     if (onotheld_mode == 0 || noun notin actor)
1787         if (AttemptToTakeObject(noun)) return;
1788     if (AfterRoutines()) return;
1789     notheld_mode = onotheld_mode;
1790     if (notheld_mode == 1 || keep_silent) return;
1791     L__M(##Take, 1, noun);
1792 ];
1793
1794 [ RemoveSub i;
1795     i = parent(noun);
1796     if (i && i has container && i hasnt open && ImplicitOpen(i)) return L__M(##Remove, 1, i);
1797     if (i ~= second)   return L__M(##Remove, 2, noun);
1798     if (i has animate) return L__M(##Take, 6, i, noun);
1799
1800     if (AttemptToTakeObject(noun)) rtrue;
1801
1802     action = ##Remove; if (AfterRoutines()) return;
1803     action = ##Take;   if (AfterRoutines()) return;
1804     if (keep_silent) return;
1805     L__M(##Remove, 3, noun);
1806 ];
1807
1808 [ DropSub;
1809     if (noun == actor)         return L__M(##PutOn, 4, noun);
1810     if (noun in parent(actor)) return L__M(##Drop, 1, noun);
1811     if (noun notin actor && ~~ImplicitTake(noun)) return L__M(##Drop, 2, noun);
1812     if (noun has worn && ImplicitDisrobe(noun)) return;
1813     move noun to parent(actor);
1814     if (AfterRoutines() || keep_silent) return;
1815     L__M(##Drop, 4, noun);
1816 ];
1817
1818 [ PutOnSub ancestor;
1819     receive_action = ##PutOn;
1820     if (second == d_obj || actor in second) <<Drop noun, actor>>;
1821     if (parent(noun) == second) return L__M(##Drop, 1, noun);
1822     if (noun notin actor && ImplicitTake(noun)) return L__M(##PutOn, 1, noun);
1823
1824     ancestor = CommonAncestor(noun, second);
1825     if (ancestor == noun) return L__M(##PutOn, 2, noun);
1826     if (ObjectIsUntouchable(second)) return;
1827
1828     if (second ~= ancestor) {
1829         action = ##Receive;
1830         if (RunRoutines(second, before)) { action = ##PutOn; return; }
1831         action = ##PutOn;
1832     }
1833     if (second hasnt supporter) return L__M(##PutOn, 3, second);
1834     if (ancestor == actor)      return L__M(##PutOn, 4, second);
1835     if (noun has worn && ImplicitDisrobe(noun)) return;
1836
1837     if (ObjectDoesNotFit(noun, second) ||
1838         LibraryExtensions.RunWhile(ext_objectdoesnotfit, false, noun, second)) return;
1839     if (AtFullCapacity(noun, second)) return L__M(##PutOn, 6, second);
1840
1841     move noun to second;
1842
1843     if (AfterRoutines()) return;
1844
1845     if (second ~= ancestor) {
1846         action = ##Receive;
1847         if (RunRoutines(second, after)) { action = ##PutOn; return; }
1848         action = ##PutOn;
1849     }
1850     if (keep_silent) return;
1851     if (multiflag) return L__M(##PutOn, 7);
1852     L__M(##PutOn, 8, noun, second);
1853 ];
1854
1855 [ InsertSub ancestor;
1856     receive_action = ##Insert;
1857     if (second == d_obj || actor in second) <<Drop noun, actor>>;
1858     if (parent(noun) == second) return L__M(##Drop, 1, noun);
1859     if (noun notin actor && ImplicitTake(noun)) return L__M(##Insert, 1, noun);
1860     ancestor = CommonAncestor(noun, second);
1861     if (ancestor == noun) return L__M(##Insert, 5, noun);
1862     if (ObjectIsUntouchable(second)) return;
1863     if (second ~= ancestor) {
1864         action = ##Receive;
1865         if (RunRoutines(second,before)) { action = ##Insert; rtrue; }
1866         action = ##Insert;
1867         if (second has container && second hasnt open && ImplicitOpen(second))
1868             return L__M(##Insert, 3, second);
1869     }
1870     if (second hasnt container) return L__M(##Insert, 2, second);
1871     if (noun has worn && ImplicitDisrobe(noun)) return;
1872
1873     if (ObjectDoesNotFit(noun, second) ||
1874         LibraryExtensions.RunWhile(ext_objectdoesnotfit, false, noun, second)) return;
1875     if (AtFullCapacity(noun, second)) return L__M(##Insert, 7, second);
1876
1877     move noun to second;
1878
1879     if (AfterRoutines()) rtrue;
1880
1881     if (second ~= ancestor) {
1882         action = ##Receive;
1883         if (RunRoutines(second, after)) { action = ##Insert; rtrue; }
1884         action = ##Insert;
1885     }
1886     if (keep_silent) rtrue;
1887     if (multiflag) return L__M(##Insert, 8, noun);
1888     L__M(##Insert, 9, noun, second);
1889 ];
1890
1891 ! ----------------------------------------------------------------------------
1892 !   Empties and transfers are routed through the actions above
1893 ! ----------------------------------------------------------------------------
1894
1895 [ TransferSub;
1896     if (noun notin actor && AttemptToTakeObject(noun)) return;
1897     if (second has supporter) <<PutOn noun second, actor>>;
1898     if (second == d_obj) <<Drop noun, actor>>;
1899     <<Insert noun second, actor>>;
1900 ];
1901
1902 [ EmptySub; second = d_obj; EmptyTSub(); ];
1903
1904 [ EmptyTSub i j k flag;
1905     if (noun == second) return L__M(##EmptyT, 4, noun);
1906     if (ObjectIsUntouchable(noun)) return;
1907     if (noun hasnt container) return L__M(##EmptyT, 1, noun);
1908     if (noun hasnt open && ImplicitOpen(noun)) return L__M(##EmptyT, 2, noun);
1909     if (second ~= d_obj) {
1910         if (second hasnt supporter) {
1911             if (second hasnt container) return L__M(##EmptyT, 1, second);
1912             if (second hasnt open && ImplicitOpen(second))
1913                 return L__M(##EmptyT, 2, second);
1914         }
1915     }
1916     i = child(noun); k = children(noun);
1917     if (i == 0) return L__M(##EmptyT, 3, noun);
1918     while (i) {
1919         j = sibling(i);
1920         flag = false;
1921         if (ObjectIsUntouchable(noun)) flag = true;
1922         if (noun hasnt container) flag = true;
1923         if (noun hasnt open) flag = true;
1924         if (second ~= d_obj) {
1925             if (second hasnt supporter) {
1926                 if (second hasnt container) flag = true;
1927                 if (second hasnt open) flag = true;
1928             }
1929         }
1930         if (k-- == 0) flag = 1;
1931         if (flag) break;
1932         if (keep_silent == 0) print (name) i, (string) COLON__TX;
1933         <Transfer i second, actor>;
1934         i = j;
1935     }
1936 ];
1937
1938 ! ----------------------------------------------------------------------------
1939 !   Gifts
1940 ! ----------------------------------------------------------------------------
1941
1942 [ GiveSub;
1943     if (noun notin actor && ImplicitTake(noun)) return L__M(##Give, 1, noun);
1944     if (second == actor) return L__M(##Give, 2, noun);
1945     if (noun has worn && ImplicitDisrobe(noun)) return;
1946     if (second == player) {
1947         move noun to player;
1948         return L__M(##Give, 4, noun);
1949     }
1950
1951     if (RunLife(second, ##Give)) return;
1952     L__M(##Give, 3, second);
1953 ];
1954
1955 [ GiveRSub; <Give second noun, actor>; ];
1956
1957 [ ShowSub;
1958     if (noun notin actor && ImplicitTake(noun)) return L__M(##Show, 1, noun);
1959     if (second == player) <<Examine noun, actor>>;
1960     if (RunLife(second, ##Show)) return;
1961     L__M(##Show, 2, second);
1962 ];
1963
1964 [ ShowRSub; <Show second noun, actor>; ];
1965
1966 ! ----------------------------------------------------------------------------
1967 !   Travelling around verbs
1968 ! ----------------------------------------------------------------------------
1969
1970 [ EnterSub ancestor j ks;
1971     if (noun has door || noun in compass) <<Go noun, actor>>;
1972     if (actor in noun) return L__M(##Enter, 1, noun);
1973     if (noun hasnt enterable) return L__M(##Enter, 2, noun, verb_word);
1974
1975     if (parent(actor) ~= parent(noun)) {
1976         ancestor = CommonAncestor(actor, noun);
1977         if (ancestor == actor or 0) return L__M(##Enter, 4, noun);
1978         while (actor notin ancestor) {
1979             j = parent(actor);
1980             ks = keep_silent;
1981             if (parent(j) ~= ancestor || noun ~= ancestor) {
1982                 L__M(##Enter, 6, j);
1983                 keep_silent = 1;
1984             }
1985             <Exit, actor>;
1986             keep_silent = ks;
1987             if (actor in j) return;
1988         }
1989         if (actor in noun) return;
1990         if (noun notin ancestor) {
1991             j = parent(noun);
1992             while (parent(j) ~= ancestor) j = parent(j);
1993             L__M(##Enter, 7, j);
1994             ks = keep_silent; keep_silent = 1;
1995             <Enter j, actor>;
1996             keep_silent = ks;
1997             if (actor notin j) return;
1998             <<Enter noun, actor>>;
1999         }
2000     }
2001
2002     if (noun has container && noun hasnt open && ImplicitOpen(noun)) return L__M(##Enter, 3, noun);
2003     move actor to noun;
2004
2005     if (AfterRoutines() || keep_silent) return;
2006     L__M(##Enter, 5, noun);
2007     if (actor == player) Locale(noun);
2008 ];
2009
2010 [ GetOffSub;
2011     if (parent(actor) == noun) <<Exit, actor>>;
2012     L__M(##GetOff, 1, noun);
2013 ];
2014
2015 [ ExitSub p;
2016     p = parent(actor);
2017     if (noun ~= nothing && noun ~= p) return L__M(##Exit, 4 ,noun);
2018     if (p == location || (location == thedark && p == real_location)) {
2019         if (actor provides posture && actor.posture) {
2020             actor.posture = 0;
2021             return L__M(##Exit, 6);
2022         }
2023         if ((location.out_to) || (location == thedark && real_location.out_to))
2024             <<Go out_obj, actor>>;
2025         return L__M(##Exit, 1);
2026     }
2027     if (p has container && p hasnt open && ImplicitOpen(p))
2028         return L__M(##Exit, 2, p);
2029
2030     if (noun == nothing) {
2031         inp1 = p;
2032         if (RunRoutines(p, before)) return;
2033     }
2034
2035     move actor to parent(p);
2036     if (player provides posture) player.posture = 0;
2037
2038     if (AfterRoutines() || keep_silent) return;
2039     L__M(##Exit, 3, p);
2040     if (actor == player && p has container) LookSub(1);
2041 ];
2042
2043 [ VagueGoSub; L__M(##VagueGo); ];
2044
2045 [ GoInSub; <<Go in_obj, actor>>; ];
2046
2047 [ GoSub i j k movewith thedir next_loc;
2048
2049     ! first, check if any PushDir object is touchable
2050     if (second && second notin Compass && ObjectIsUntouchable(second)) return;
2051
2052     movewith = 0;
2053     i = parent(actor);
2054     if ((location ~= thedark && i ~= location) || (location == thedark && i ~= real_location)) {
2055         j = location;
2056         if (location == thedark) location = real_location;
2057         k = RunRoutines(i, before); if (k ~= 3) location = j;
2058         if (k == 1) {
2059            movewith = i; i = parent(i);
2060         }
2061         else {
2062             if (k) rtrue;
2063             if (ImplicitExit(i)) return L__M(##Go, 1, i);
2064             i = parent(actor);
2065         }
2066     }
2067
2068     thedir = noun.door_dir;
2069     if (metaclass(thedir) == Routine) thedir = RunRoutines(noun, door_dir);
2070
2071     next_loc = i.thedir; k = metaclass(next_loc);
2072     if (k == String) { print (string) next_loc; new_line; rfalse; }
2073     if (k == Routine) {
2074         next_loc = RunRoutines(i, thedir);
2075         if (next_loc == 1) rtrue;
2076     }
2077
2078     if (k == nothing || next_loc == 0) {
2079         if (i.cant_go ~= 0 or CANTGO__TX) PrintOrRun(i, cant_go);
2080         else                              L__M(##Go, 2);
2081         rfalse;
2082     }
2083     if (next_loc has door) {
2084         if (next_loc has concealed) return L__M(##Go, 2);
2085         if (next_loc hasnt open && ImplicitOpen(next_loc)) {
2086             if (noun == u_obj) return L__M(##Go, 3, next_loc);
2087             if (noun == d_obj) return L__M(##Go, 4, next_loc);
2088             return L__M(##Go, 5, next_loc);
2089         }
2090         k = RunRoutines(next_loc, door_to);
2091         if (k == 0) return L__M(##Go, 6, next_loc);
2092         if (k == 1) rtrue;
2093         next_loc = k;
2094     }
2095
2096     action = ##Going;
2097     if (RunRoutines(next_loc, before)) { action = ##Go; return; }
2098     action = ##Go;
2099
2100     if (movewith == 0) move actor to next_loc; else move movewith to next_loc;
2101     if (actor ~= player) return L__M(##Go, 7);
2102
2103     k = location; location = next_loc;
2104     MoveFloatingObjects();
2105     if (OffersLight(location))
2106         lightflag = true;
2107     else {
2108         lightflag = false;
2109         if (k == thedark) {
2110             if(DarkToDark() == false) ! From real_location To location
2111                 LibraryExtensions.RunAll(ext_darktodark);
2112             if (deadflag) rtrue;
2113         }
2114         location = thedark;
2115     }
2116     NoteDeparture(); real_location = next_loc;
2117     action = ##Going;
2118     if (RunRoutines(prev_location, after)) { action = ##Go; return; }
2119     action = ##Go;
2120     if (AfterRoutines() || keep_silent) return;
2121     LookSub(1);
2122 ];
2123
2124 ! ----------------------------------------------------------------------------
2125 !   Describing the world.  SayWhatsOn(object) does just that (producing
2126 !   no text if nothing except possibly "scenery" and "concealed" items are).
2127 !   Locale(object) runs through the "tail end" of a Look-style room
2128 !   description for the contents of the object, printing up suitable
2129 !   descriptions as it goes.
2130 ! ----------------------------------------------------------------------------
2131
2132 [ SayWhatsOn descon j f;
2133     if (descon == parent(player)) rfalse;
2134     objectloop (j in descon)
2135         if (j hasnt concealed && j hasnt scenery) f = 1;
2136     if (f == 0) rfalse;
2137     L__M(##Look, 4, descon);
2138 ];
2139
2140 [ NotSupportingThePlayer o i;
2141     i = parent(player);
2142     while (i && i ~= visibility_ceiling) {
2143         if (i == o) rfalse;
2144         i = parent(i);
2145         if (i && i hasnt supporter) rtrue;
2146     }
2147     rtrue;
2148 ];
2149 ! modified with the fix for L61122
2150 [ Locale descin text_without_ALSO text_with_ALSO
2151     o p num_objs must_print_ALSO;
2152     objectloop (o in descin) give o ~workflag;
2153     num_objs = 0;
2154     objectloop (o in descin)
2155         if (o hasnt concealed && NotSupportingThePlayer(o)) {
2156             #Ifndef MANUAL_PRONOUNS;
2157             PronounNotice(o);
2158             #Endif;
2159             if (o has scenery) {
2160                 if (o has supporter && child(o)) SayWhatsOn(o);
2161             }
2162             else {
2163                 give o workflag; num_objs++;
2164                 p = initial;
2165                 if ((o has door or container) && o has open && o provides when_open) {
2166                     p = when_open; jump Prop_Chosen;
2167                 }
2168                 if ((o has door or container) && o hasnt open && o provides when_closed) {
2169                     p = when_closed; jump Prop_Chosen;
2170                 }
2171                 if (o has switchable && o has on && o provides when_on) {
2172                     p = when_on; jump Prop_Chosen;
2173                 }
2174                 if (o has switchable && o hasnt on && o provides when_off) {
2175                     p = when_off;
2176                 }
2177
2178               .Prop_Chosen;
2179
2180                 if (o.&describe && RunRoutines(o, describe)) {
2181                     must_print_ALSO = true;
2182                     give o ~workflag; num_objs--;
2183                     continue;
2184                 }
2185                 if (o.p && (o hasnt moved || p ~= initial)) {
2186                     new_line;
2187                     PrintOrRun(o, p);
2188                     must_print_ALSO = true;
2189                     give o ~workflag; num_objs--;
2190                     if (o has supporter && child(o)) SayWhatsOn(o);
2191                 }
2192             }
2193         }
2194
2195     if (num_objs == 0) return 0;
2196
2197     if (actor ~= player) give actor concealed;
2198     if (text_without_ALSO) {
2199         new_line;
2200         if (must_print_ALSO) print (string) text_with_ALSO, " ";
2201         else print (string) text_without_ALSO, " ";
2202         WriteListFrom(child(descin),
2203           ENGLISH_BIT+RECURSE_BIT+PARTINV_BIT+TERSE_BIT+CONCEAL_BIT+WORKFLAG_BIT);
2204     }
2205     else {
2206         if (must_print_ALSO) L__M(##Look, 5, descin);
2207         else L__M(##Look, 6, descin);
2208     }
2209     if (actor ~= player) give actor ~concealed;
2210     return num_objs;
2211 ];
2212
2213 ! ----------------------------------------------------------------------------
2214 !   Looking.  LookSub(1) is allowed to abbreviate long descriptions, but
2215 !     LookSub(0) (which is what happens when the Look action is generated)
2216 !     isn't.  (Except that these are over-ridden by the player-set lookmode.)
2217 ! ----------------------------------------------------------------------------
2218
2219 [ LMode1Sub; lookmode=1; L__M(##LMode1); ];  ! Brief
2220
2221 [ LMode2Sub; lookmode=2; L__M(##LMode2); ];  ! Verbose
2222
2223 [ LMode3Sub; lookmode=3; L__M(##LMode3); ];  ! Superbrief
2224
2225 [ LModeNormalSub;       ! 'normal' value: the default, or as set in Initialise()
2226     switch (initial_lookmode) {
2227       1:       <<LMode1>>;
2228       3:       <<LMode3>>;
2229       default: <<LMode2>>;
2230     }
2231 ];
2232
2233 [ NoteArrival descin;
2234     if (location ~= lastdesc) {
2235         if (location.initial) PrintOrRun(location, initial);
2236         if (location == thedark) { lastdesc = thedark; return; }
2237         descin = location;
2238         if(NewRoom() == false) LibraryExtensions.RunAll(ext_newroom);
2239         lastdesc = descin;
2240     }
2241 ];
2242
2243 [ NoteDeparture;
2244     prev_location = real_location;
2245 ];
2246
2247 [ ScoreArrival;
2248     if (location hasnt visited) {
2249         give location visited;
2250         if (location has scored) {
2251             score = score + ROOM_SCORE;
2252             places_score = places_score + ROOM_SCORE;
2253         }
2254     }
2255 ];
2256
2257 [ FindVisibilityLevels visibility_levels;
2258     visibility_levels = 1;
2259     visibility_ceiling = parent(player);
2260     while ((parent(visibility_ceiling)) &&
2261                   (visibility_ceiling hasnt container || visibility_ceiling has open or transparent)) {
2262         visibility_ceiling = parent(visibility_ceiling);
2263         visibility_levels++;
2264     }
2265     return visibility_levels;
2266 ];
2267
2268 [ LookSub allow_abbrev  visibility_levels i j k nl_flag;
2269     if (parent(player) == 0) return RunTimeError(10);
2270
2271   .MovedByInitial;
2272
2273     if (location == thedark) { visibility_ceiling = thedark; NoteArrival(); }
2274     else {
2275         visibility_levels = FindVisibilityLevels();
2276         if (visibility_ceiling == location) {
2277             NoteArrival();
2278             if (visibility_ceiling ~= location) jump MovedByInitial;
2279         }
2280     }
2281     ! Printing the top line: e.g.
2282     ! Octagonal Room (on the table) (as Frodo)
2283     new_line;
2284     #Ifdef TARGET_ZCODE;
2285     style bold;
2286     #Ifnot; ! TARGET_GLULX;
2287     glk_set_style(style_Subheader);
2288     #Endif; ! TARGET_
2289     if (visibility_levels == 0) print (name) thedark;
2290     else {
2291         if (visibility_ceiling ~= location) print (The) visibility_ceiling;
2292         else print (name) visibility_ceiling;
2293     }
2294     #Ifdef TARGET_ZCODE;
2295     style roman;
2296     #Ifnot; ! TARGET_GLULX;
2297     glk_set_style(style_Normal);
2298     #Endif; ! TARGET_
2299
2300     for (j=1,i=parent(player) : j<visibility_levels : j++,i=parent(i))
2301         if (i has supporter) L__M(##Look, 1, i);
2302         else                 L__M(##Look, 2, i);
2303
2304     if (print_player_flag == 1) L__M(##Look, 3, player);
2305     new_line;
2306
2307     ! The room description (if visible)
2308
2309     if (lookmode < 3 && visibility_ceiling == location) {
2310         if ((allow_abbrev ~= 1) || (lookmode == 2) || (location hasnt visited)) {
2311             if (location.&describe) RunRoutines(location, describe);
2312             else {
2313                 if (location.description == 0) RunTimeError(11, location, description);
2314                 else PrintOrRun(location, description);
2315             }
2316         }
2317     }
2318
2319     if (visibility_ceiling == location) nl_flag = 1;
2320
2321     if (visibility_levels == 0) Locale(thedark);
2322     else {
2323         for (i=player,j=visibility_levels : j>0 : j--,i=parent(i)) give i workflag;
2324
2325         for (j=visibility_levels : j>0 : j--) {
2326             for (i=player,k=0 : k<j : k++) i=parent(i);
2327             if (i.inside_description) {
2328                 if (nl_flag) new_line; else nl_flag = 1;
2329                     PrintOrRun(i,inside_description);
2330                 }
2331             if (Locale(i)) nl_flag=1;
2332         }
2333     }
2334
2335     if(LookRoutine() == false) LibraryExtensions.RunAll(ext_lookroutine);
2336     ScoreArrival();
2337     action = ##Look;
2338     AfterRoutines();
2339 ];
2340
2341 [ ExamineSub i;
2342     if (location == thedark) return L__M(##Examine, 1, noun);
2343     i = noun.description;
2344     if (i == 0) {
2345         if (noun has container)
2346             if (noun has open or transparent) <<Search noun, actor>>;
2347             else return L__M(##Search, 5, noun);
2348         if (noun has switchable) { L__M(##Examine, 3, noun); rfalse; }
2349         return L__M(##Examine, 2, noun);
2350     }
2351     i = PrintOrRun(noun, description);
2352     if (i < 2 && noun has switchable) L__M(##Examine, 3, noun);
2353     AfterRoutines();
2354 ];
2355
2356 [ LookUnderSub;
2357     if (location == thedark) return L__M(##LookUnder, 1, noun);
2358     L__M(##LookUnder, 2);
2359 ];
2360
2361 [ VisibleContents o  i f;
2362     objectloop (i in o) if (i hasnt concealed or scenery) f++;
2363     return f;
2364 ];
2365
2366 [ SearchSub f;
2367     if (location == thedark) return L__M(##Search, 1, noun);
2368     if (ObjectIsUntouchable(noun)) return;
2369     f = VisibleContents(noun);
2370     if (noun has supporter) {
2371         if (f == 0) return L__M(##Search, 2, noun);
2372         return L__M(##Search, 3, noun);
2373     }
2374     if (noun hasnt container) return L__M(##Search, 4, noun);
2375     if (noun hasnt transparent or open && ImplicitOpen(noun)) return L__M(##Search, 5, noun);
2376     if (AfterRoutines()) return;
2377
2378     if (f == 0) return L__M(##Search, 6, noun);
2379     L__M(##Search, 7, noun);
2380 ];
2381
2382 ! ----------------------------------------------------------------------------
2383 !   Verbs which change the state of objects without moving them
2384 ! ----------------------------------------------------------------------------
2385
2386 [ UnlockSub;
2387     if (ObjectIsUntouchable(noun)) return;
2388     if (noun hasnt lockable)     return L__M(##Unlock, 1, noun);
2389     if (noun hasnt locked)       return L__M(##Unlock, 2, noun);
2390     if (noun.with_key ~= second) return L__M(##Unlock, 3, second);
2391
2392     give noun ~locked;
2393
2394     if (AfterRoutines() || keep_silent) return;
2395     L__M(##Unlock, 4, noun);
2396 ];
2397
2398 [ LockSub;
2399     if (ObjectIsUntouchable(noun)) return;
2400     if (noun hasnt lockable) return L__M(##Lock, 1, noun);
2401     if (noun has locked)     return L__M(##Lock, 2 ,noun);
2402     if (noun has open && ImplicitClose(noun)) return L__M(##Lock, 3, noun);
2403     if (noun.with_key ~= second) return L__M(##Lock, 4, second);
2404
2405     give noun locked;
2406     if (AfterRoutines() || keep_silent) return;
2407     L__M(##Lock, 5, noun);
2408 ];
2409
2410 [ SwitchonSub;
2411     if (ObjectIsUntouchable(noun)) return;
2412     if (noun hasnt switchable) return L__M(##SwitchOn, 1, noun);
2413     if (noun has on)           return L__M(##SwitchOn, 2, noun);
2414
2415     give noun on;
2416     if (AfterRoutines() || keep_silent) return;
2417     L__M(##SwitchOn, 3, noun);
2418 ];
2419
2420 [ SwitchoffSub;
2421     if (ObjectIsUntouchable(noun)) return;
2422     if (noun hasnt switchable) return L__M(##SwitchOff, 1, noun);
2423     if (noun hasnt on)         return L__M(##SwitchOff, 2, noun);
2424
2425     give noun ~on;
2426     if (AfterRoutines() || keep_silent) return;
2427     L__M(##SwitchOff, 3, noun);
2428 ];
2429
2430 [ OpenSub;
2431     if (ObjectIsUntouchable(noun)) return;
2432     if (noun hasnt openable) return L__M(##Open, 1, noun);
2433     if (noun has locked && ImplicitUnlock(noun)) return L__M(##Open, 2, noun);
2434     if (noun has open)       return L__M(##Open, 3, noun);
2435     give noun open;
2436
2437     if (keep_silent || AfterRoutines()) return;
2438
2439     if (noun hasnt container)
2440         return L__M(##Open, 5, noun);
2441
2442     if ((noun has container && location ~= thedark && VisibleContents(noun)
2443          && IndirectlyContains(noun, player)) == 0) {
2444          if (noun hasnt transparent && noun hasnt door) return L__M(##Open, 4, noun);
2445     }
2446     L__M(##Open, 5, noun);
2447 ];
2448
2449 [ CloseSub;
2450     if (ObjectIsUntouchable(noun)) return;
2451     if (noun hasnt openable) return L__M(##Close, 1, noun);
2452     if (noun hasnt open)     return L__M(##Close, 2, noun);
2453
2454     give noun ~open;
2455     if (AfterRoutines() || keep_silent) return;
2456     L__M(##Close, 3, noun);
2457 ];
2458
2459 [ DisrobeSub;
2460     if (ObjectIsUntouchable(noun)) return;
2461     if (noun hasnt worn) return L__M(##Disrobe, 1, noun);
2462
2463     give noun ~worn;
2464     if (AfterRoutines() || keep_silent) return;
2465     L__M(##Disrobe, 2, noun);
2466 ];
2467
2468 [ WearSub;
2469     if (ObjectIsUntouchable(noun)) return;
2470     if (noun hasnt clothing)    return L__M(##Wear, 1, noun);
2471     if (noun notin actor && ImplicitTake(noun)) return L__M(##Wear, 2, noun);
2472     if (noun has worn)          return L__M(##Wear, 3, noun);
2473
2474     give noun worn;
2475     if (AfterRoutines() || keep_silent) return;
2476     L__M(##Wear, 4, noun);
2477 ];
2478
2479 [ EatSub;
2480     if (ObjectIsUntouchable(noun)) return;
2481     if (noun hasnt edible) return L__M(##Eat, 1, noun);
2482     if (noun has worn && ImplicitDisrobe(noun)) return;
2483
2484     remove noun;
2485     if (AfterRoutines() || keep_silent) return;
2486     L__M(##Eat, 2, noun);
2487 ];
2488
2489 ! ----------------------------------------------------------------------------
2490 !   Verbs which are really just stubs (anything which happens for these
2491 !   actions must happen in before rules)
2492 ! ----------------------------------------------------------------------------
2493
2494 [ AllowPushDir i;
2495     if (parent(second) ~= compass) return L__M(##PushDir, 2, noun);
2496     if (second == u_obj or d_obj)  return L__M(##PushDir, 3, noun);
2497     AfterRoutines(); i = noun; move i to actor;
2498     <Go second, actor>;
2499     if (location == thedark) move i to real_location;
2500     else                     move i to location;
2501 ];
2502
2503 [ AnswerSub;
2504     if (second && RunLife(second,##Answer)) rfalse;
2505     L__M(##Answer, 1, noun);
2506 ];
2507
2508 [ AskSub;
2509     if (RunLife(noun,##Ask)) rfalse;
2510     L__M(##Ask, 1, noun);
2511 ];
2512
2513 [ AskForSub;
2514     if (noun == player) <<Inv, actor>>;
2515     L__M(##Order, 1, noun);
2516 ];
2517
2518 [ AskToSub; L__M(##Order, 1, noun); ];
2519
2520 [ AttackSub;
2521     if (ObjectIsUntouchable(noun)) return;
2522     if (noun has animate && RunLife(noun, ##Attack)) rfalse;
2523     L__M(##Attack, 1, noun);
2524 ];
2525
2526 [ BlowSub; L__M(##Blow, 1, noun); ];
2527
2528 [ BurnSub;
2529     if (noun has animate) return L__M(##Burn, 2, noun);
2530     L__M(##Burn, 1, noun);
2531 ];
2532
2533 [ BuySub; L__M(##Buy, 1, noun); ];
2534
2535 [ ClimbSub;
2536     if (noun has animate) return L__M(##Climb, 2, noun);
2537     L__M(##Climb, 1, noun);
2538 ];
2539
2540 [ ConsultSub; L__M(##Consult, 1, noun); ];
2541
2542 [ CutSub;
2543     if (noun has animate) return L__M(##Cut, 2, noun);
2544     L__M(##Cut, 1, noun);
2545 ];
2546
2547 [ DigSub; L__M(##Dig, 1, noun); ];
2548
2549 [ DrinkSub; L__M(##Drink, 1, noun); ];
2550
2551 [ FillSub;
2552     if (second == nothing) return L__M(##Fill, 1, noun);
2553     L__M(##Fill, 2, noun, second);
2554 ];
2555
2556 [ JumpSub; L__M(##Jump, 1, noun); ];
2557
2558 [ JumpInSub;
2559     if (noun has animate) return L__M(##JumpIn, 2, noun);
2560     if (noun has enterable) <<Enter noun>>;
2561     L__M(##JumpIn, 1, noun);
2562 ];
2563
2564 [ JumpOnSub;
2565     if (noun has animate) return L__M(##JumpOn, 2, noun);
2566     if (noun has enterable && noun has supporter) <<Enter noun>>;
2567     L__M(##JumpOn, 1, noun);
2568 ];
2569
2570 [ JumpOverSub;
2571     if (noun has animate) return L__M(##JumpOver, 2, noun);
2572     L__M(##JumpOver, 1, noun);
2573 ];
2574
2575 [ KissSub;
2576     if (ObjectIsUntouchable(noun)) return;
2577     if (RunLife(noun, ##Kiss)) return;
2578     if (noun == actor) return L__M(##Touch, 3, noun);
2579     L__M(##Kiss, 1, noun);
2580 ];
2581
2582 [ ListenSub; L__M(##Listen, 1, noun); ];
2583
2584 [ MildSub; L__M(##Mild, 1, noun); ];
2585
2586 [ NoSub; L__M(##No); ];
2587
2588 [ PraySub; L__M(##Pray, 1, noun); ];
2589
2590 [ PullSub;
2591     if (ObjectIsUntouchable(noun)) return;
2592     if (noun == player)   return L__M(##Pull, 1, noun);
2593     if (noun == actor)    return L__M(##Pull, 6, noun);
2594     if (noun has static)  return L__M(##Pull, 2, noun);
2595     if (noun has scenery) return L__M(##Pull, 3, noun);
2596     if (noun has animate) return L__M(##Pull, 5, noun);
2597     L__M(##Pull, 4, noun);
2598 ];
2599
2600 [ PushSub;
2601     if (ObjectIsUntouchable(noun)) return;
2602     if (noun == player)   return L__M(##Push, 1, noun);
2603     if (noun == actor)    return L__M(##Push, 5, noun);
2604     if (noun has static)  return L__M(##Push, 2, noun);
2605     if (noun has scenery) return L__M(##Push, 3, noun);
2606     if (noun has animate) return L__M(##Push, 5, noun);
2607     L__M(##Push, 4, noun);
2608 ];
2609
2610 [ PushDirSub; L__M(##PushDir, 1, noun); ];
2611
2612 [ RubSub;
2613     if (ObjectIsUntouchable(noun)) return;
2614     if (noun has animate) return L__M(##Rub, 2, noun);
2615     L__M(##Rub, 1, noun);
2616 ];
2617
2618 [ SetSub; L__M(##Set, 1, noun); ];
2619
2620 [ SetToSub; L__M(##SetTo, 1, noun); ];
2621
2622 [ SingSub; L__M(##Sing, 1, noun); ];
2623
2624 [ SleepSub; L__M(##Sleep, 1, noun); ];
2625
2626 [ SmellSub;
2627     if (noun ~= nothing && noun has animate) return L__M(##Smell, 2, noun);
2628     L__M(##Smell, 1, noun);
2629 ];
2630
2631 [ SorrySub; L__M(##Sorry, 1, noun); ];
2632
2633 [ SqueezeSub;
2634     if (ObjectIsUntouchable(noun)) return;
2635     if (noun has animate && noun ~= player) return L__M(##Squeeze, 1, noun);
2636     L__M(##Squeeze, 2, noun);
2637 ];
2638
2639 [ StrongSub; L__M(##Strong, 1, noun); ];
2640
2641 [ SwimSub; L__M(##Swim, 1, noun); ];
2642
2643 [ SwingSub; L__M(##Swing, 1, noun); ];
2644
2645 [ TasteSub;
2646     if (ObjectIsUntouchable(noun)) return;
2647     if (noun has animate) return L__M(##Taste, 2, noun);
2648     L__M(##Taste, 1, noun);
2649 ];
2650
2651 [ TellSub;
2652     if (noun == actor) return L__M(##Tell, 1, noun);
2653     if (RunLife(noun, ##Tell)) return;
2654     L__M(##Tell, 2, noun);
2655 ];
2656
2657 [ ThinkSub; L__M(##Think, 1, noun); ];
2658
2659 [ ThrowAtSub;
2660     if (ObjectIsUntouchable(noun)) return;
2661     if (second == nothing) return L__M(##ThrowAt, 1, noun);
2662     if (second > 1) {
2663         action = ##ThrownAt;
2664         if (RunRoutines(second, before)) { action = ##ThrowAt; rtrue; }
2665         action = ##ThrowAt;
2666     }
2667     if (noun has worn && ImplicitDisrobe(noun)) return;
2668     if (second hasnt animate) return L__M(##ThrowAt, 1, noun);
2669     if (RunLife(second, ##ThrowAt)) return;
2670     L__M(##ThrowAt, 2, noun);
2671 ];
2672
2673 [ TieSub;
2674     if (noun has animate) return L__M(##Tie, 2, noun);
2675     L__M(##Tie, 1, noun);
2676 ];
2677
2678 [ TouchSub;
2679     if (noun == actor)   return L__M(##Touch, 3, noun);
2680     if (ObjectIsUntouchable(noun)) return;
2681     if (noun has animate) return L__M(##Touch, 1, noun);
2682     L__M(##Touch, 2,noun);
2683 ];
2684
2685 [ TurnSub;
2686     if (ObjectIsUntouchable(noun)) return;
2687     if (noun == player)    return L__M(##Turn, 1, noun);
2688     if (noun == actor)     return L__M(##Turn, 5, noun);
2689     if (noun has static)   return L__M(##Turn, 2, noun);
2690     if (noun has scenery)  return L__M(##Turn, 3, noun);
2691     if (noun has animate)  return L__M(##Turn, 5, noun);
2692     L__M(##Turn, 4, noun);
2693 ];
2694
2695 [ WaitSub;
2696     if (AfterRoutines()) rtrue;
2697     L__M(##Wait, 1, noun);
2698 ];
2699
2700 [ WakeSub; L__M(##Wake, 1, noun); ];
2701
2702 [ WakeOtherSub;
2703     if (ObjectIsUntouchable(noun)) return;
2704     if (RunLife(noun, ##WakeOther)) return;
2705     L__M(##WakeOther, 1, noun);
2706 ];
2707
2708 [ WaveSub;
2709     if (noun == player) return L__M(##Wave, 2 ,noun, second);
2710     if (noun == actor) return L__M(##Wave, 3, noun, second);
2711     if (noun notin actor && ImplicitTake(noun)) return L__M(##Wave, 1, noun);
2712     L__M(##Wave, 2, noun, second);
2713 ];
2714
2715 [ WaveHandsSub;
2716     if (noun) return L__M(##WaveHands, 2, noun);
2717     L__M(##WaveHands, 1, noun); ];
2718
2719 [ YesSub; L__M(##Yes); ];
2720
2721 ! ----------------------------------------------------------------------------
2722 !   Debugging verbs
2723 ! ----------------------------------------------------------------------------
2724
2725 #Ifdef DEBUG;
2726
2727 [ TraceOnSub; parser_trace = 1; "[Trace on.]"; ];
2728
2729 [ TraceLevelSub;
2730     parser_trace = noun;
2731     print "[Parser tracing set to level ", parser_trace, ".]^";
2732 ];
2733
2734 [ TraceOffSub; parser_trace = 0; "Trace off."; ];
2735
2736 [ RoutinesOnSub;
2737     debug_flag = debug_flag |  DEBUG_MESSAGES;
2738     "[Message listing on.]";
2739 ];
2740
2741 [ RoutinesOffSub;
2742     debug_flag = debug_flag & ~DEBUG_MESSAGES;
2743     "[Message listing off.]";
2744 ];
2745
2746 [ RoutinesVerboseSub;
2747     debug_flag = debug_flag | (DEBUG_VERBOSE|DEBUG_MESSAGES);
2748     "[Verbose message listing on.]";
2749 ];
2750
2751 [ ActionsOnSub;
2752     debug_flag = debug_flag |  DEBUG_ACTIONS;
2753     "[Action listing on.]";
2754 ];
2755
2756 [ ActionsOffSub;
2757     debug_flag = debug_flag & ~DEBUG_ACTIONS;
2758     "[Action listing off.]";
2759 ];
2760
2761 [ TimersOnSub;
2762     debug_flag = debug_flag |  DEBUG_TIMERS;
2763     "[Timers listing on.]";
2764 ];
2765
2766 [ TimersOffSub;
2767     debug_flag = debug_flag & ~DEBUG_TIMERS;
2768     "[Timers listing off.]";
2769 ];
2770
2771 #Ifdef VN_1610;
2772
2773 [ ChangesOnSub;   debug_flag = debug_flag |  DEBUG_CHANGES;  "[Changes listing on.]"; ];
2774 [ ChangesOffSub;  debug_flag = debug_flag & ~DEBUG_CHANGES;  "[Changes listing off.]"; ];
2775
2776 #Ifnot;
2777
2778 [ ChangesOnSub; "[Changes listing available only from Inform 6.2 onwards.]"; ];
2779
2780 [ ChangesOffSub; "[Changes listing available only from Inform 6.2 onwards.]"; ];
2781
2782 #Endif; ! VN_1610
2783
2784 #Ifdef TARGET_ZCODE;
2785
2786 [ PredictableSub i;
2787     i = random(-100);
2788     "[Random number generator now predictable.]";
2789 ];
2790
2791 #Ifnot; ! TARGET_GLULX;
2792
2793 [ PredictableSub;
2794     @setrandom 100;
2795     "[Random number generator now predictable.]";
2796 ];
2797
2798 #Endif; ! TARGET_;
2799
2800 [ XTestMove obj dest;
2801     if (~~obj ofclass Object) "[Not an object.]";
2802     if (~~dest ofclass Object) "[Destination not an object.]";
2803     if ((obj <= InformLibrary) || (obj == LibraryMessages) || (obj in 1))
2804         "[Can't move ", (name) obj, ": it's a system object.]";
2805     while (dest) {
2806         if (dest == obj) "[Can't move ", (name) obj, ": it would contain itself.]";
2807         dest = parent(dest);
2808     }
2809     rfalse;
2810 ];
2811
2812 [ XPurloinSub;
2813     if (XTestMove(noun, player)) return;
2814     move noun to player; give noun moved ~concealed;
2815     "[Purloined.]";
2816 ];
2817
2818 [ XAbstractSub;
2819     if (XTestMove(noun, second)) return;
2820     move noun to second;
2821     "[Abstracted.]";
2822 ];
2823
2824 [ XObj obj f;
2825     if (parent(obj) == 0) print (name) obj; else print (a) obj;
2826     print " (", obj, ") ";
2827     if (f && parent(obj))
2828         print "in ~", (name) parent(obj), "~ (", parent(obj), ")";
2829     new_line;
2830     if (child(obj) == 0) rtrue;
2831     if (obj == Class) ! ???
2832         WriteListFrom(child(obj), NEWLINE_BIT+INDENT_BIT+ALWAYS_BIT+ID_BIT+NOARTICLE_BIT, 1);
2833     else
2834         WriteListFrom(child(obj), NEWLINE_BIT+INDENT_BIT+ALWAYS_BIT+ID_BIT+FULLINV_BIT, 1);
2835 ];
2836
2837 [ XTreeSub i;
2838     if (noun && ~~noun ofclass Object) "[Not an object.]";
2839     if (noun == 0) {
2840         objectloop (i)
2841             if (i ofclass Object && parent(i) == 0) XObj(i);
2842     }
2843     else XObj(noun, true);
2844 ];
2845
2846 [ GotoSub;
2847     if ((~~noun ofclass Object) || parent(noun)) "[Not a safe place.]";
2848     PlayerTo(noun);
2849 ];
2850
2851 [ GoNearSub x;
2852     if (~~noun ofclass Object) "[Not a safe place.]";
2853     x = noun;
2854     while (parent(x)) x = parent(x);
2855     PlayerTo(x);
2856 ];
2857
2858 [ Print_ScL obj; print_ret ++x_scope_count, ": ", (a) obj, " (", obj, ")"; ];
2859
2860 [ ScopeSub;
2861     if (noun && ~~noun ofclass Object) "[Not an object.]";
2862     x_scope_count = 0;
2863     LoopOverScope(Print_ScL, noun);
2864     if (x_scope_count == 0) "Nothing is in scope.";
2865 ];
2866
2867 #Ifdef TARGET_GLULX;
2868
2869 [ GlkListSub id val;
2870     id = glk_window_iterate(0, gg_arguments);
2871     while (id) {
2872         print "Window ", id, " (", gg_arguments-->0, "): ";
2873         val = glk_window_get_type(id);
2874         switch (val) {
2875           1: print "pair";
2876           2: print "blank";
2877           3: print "textbuffer";
2878           4: print "textgrid";
2879           5: print "graphics";
2880           default: print "unknown";
2881         }
2882         val = glk_window_get_parent(id);
2883         if (val) print ", parent is window ", val;
2884         else     print ", no parent (root)";
2885         val = glk_window_get_stream(id);
2886         print ", stream ", val;
2887         val = glk_window_get_echo_stream(id);
2888         if (val) print ", echo stream ", val;
2889         print "^";
2890         id = glk_window_iterate(id, gg_arguments);
2891     }
2892     id = glk_stream_iterate(0, gg_arguments);
2893     while (id) {
2894         print "Stream ", id, " (", gg_arguments-->0, ")^";
2895         id = glk_stream_iterate(id, gg_arguments);
2896     }
2897     id = glk_fileref_iterate(0, gg_arguments);
2898     while (id) {
2899         print "Fileref ", id, " (", gg_arguments-->0, ")^";
2900         id = glk_fileref_iterate(id, gg_arguments);
2901     }
2902     val = glk_gestalt(gestalt_Sound, 0);
2903     if (val) {
2904         id = glk_schannel_iterate(0, gg_arguments);
2905         while (id) {
2906             print "Soundchannel ", id, " (", gg_arguments-->0, ")^";
2907             id = glk_schannel_iterate(id, gg_arguments);
2908         }
2909     }
2910 ];
2911
2912 #Endif; ! TARGET_;
2913
2914 #Endif; ! DEBUG
2915
2916 ! ----------------------------------------------------------------------------
2917 !   Finally: the mechanism for library text (the text is in the language defn)
2918 ! ----------------------------------------------------------------------------
2919
2920 [ L__M act n x1 x2 s;
2921     if (keep_silent == 2) return;
2922     s = sw__var;
2923     sw__var = act;
2924     if (n == 0) n = 1;
2925     L___M(n, x1, x2);
2926     sw__var = s;
2927 ];
2928
2929 [ L___M n x1 x2 s;
2930     s = action;
2931     lm_n = n;
2932     lm_o = x1;
2933     lm_s = x2;
2934     action = sw__var;
2935     if (RunRoutines(LibraryMessages, before))             { action = s; rfalse; }
2936     if (LibraryExtensions.RunWhile(ext_messages, false )) { action = s; rfalse; }
2937     action = s;
2938     LanguageLM(n, x1, x2);
2939 ];
2940
2941 ! ==============================================================================
2942
2943 Undef LIBRARY_STAGE; Constant LIBRARY_STAGE = AFTER_VERBLIB;
2944
2945 #Ifnot;         ! LIBRARY_STAGE < AFTER_VERBLIB but ~= AFTER_PARSER
2946                         ! (this shouldn't happen because if 'parser' isn't there, LIBRARY_STAGE isn't defined)
2947 Message "Error: 'parser' needs to be correctly included before including 'verblib'. This will cause a big number of errors!";
2948 #Endif;
2949
2950 #Ifnot;         ! LIBRARY_STAGE >= AFTER_VERBLIB: already included
2951 Message "Warning: 'verblib' included twice; ignoring second inclusion. (Ignore this if this is on purpose.)";
2952 #Endif;
2953
2954 #Ifnot;         ! LIBRARY_STAGE is not defined (likely, 'parser' hasn't been included)
2955 Message "Error: 'parser' needs to be correctly included before including 'verblib'. This will cause a big number of errors!";
2956 #Endif;
2957
2958 ! ==============================================================================