Bump release number and stuff to prepare for new release.
[rfk-inform.git] / kitten.inf
1 ! robotfindskitten
2 ! A Zen Simulation
3 ! Release 8 / Serial number 19xxxx / Inform v6.34
4 !
5 !     [-]       |\_/|        http://www.robotfindskitten.org
6 !     (+)=C     |o o|__      Leonard Richardson (C) 1997, 2000
7 !     | |       --*--__\     David Griffith (C) 2002-2019  (Inform Edition)
8 !     OOO       C_C(____)
9 !
10 !
11 ! This Zen simulation is based on the C version v1600003.248b
12 ! by Leonard Richardson (C) 1997, 2000.
13 ! Written originally for the Nerth Pork robotfindskitten contest.
14 ! Reimplemented in Inform by David Griffith (C) 2002.
15 !
16 ! Lots more information on robotfindskitten is available at
17 ! http://www.robotfindskitten.org.
18 !
19 !
20 ! In this game, you are Robot (#).  Your job is to find Kitten.  This
21 ! task is complicated by the existance of various things which are not
22 ! kitten.  Robot must touch items to determine if they are Kitten or
23 ! not.  Move Robot with the cursor keys, the numeric keypad, or
24 ! using the vi/rogue movement keys. The game ends when robotfindskitten.
25 ! Alternatively, you may end the game by hitting the Esc or Q keys.
26 !
27
28 ! Notes:
29 !       1) More than half of the code is taken up by non kitten items
30 !       (NKIs).  When I compiled the code with just five messages and
31 !       no debugging code, the resulting binary was less than 10k bytes.
32 !
33 !       2) If it wasn't already abundantly obvious, this program won't
34 !       compile to Glulx because of copious use of Z-machine assembly
35 !       instructions.
36 !       
37 !       3) Compiling for V5 or higher is required due to "style" calls.
38 !       Is there a reason why someone would want to compile this for V4
39 !       or previous?
40
41 !Switches xv5s;
42
43 Switches "d2~S";
44
45
46 Constant Nonkitten_Default 20;
47
48 ! Maxmimum possible number of non-kitten items on the playfield at once.
49 ! For whatever reason, this cannot be set dynamically.
50 !
51 Constant Nonkitten_Max  589;
52
53 Release 8;
54 !Serial "19xxxx";
55
56 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
57
58 Constant Story "robotfindskitten";
59 Constant Headline "^A Zen Simulation^";
60
61 ! NKIs are generated with nki2inf.pl and put into nki.inf
62 Include "nki.inf";
63
64 Constant Anim_Meet      10;     ! Number of spaces from the left where
65                                 !  Robot and Kitten meet during animation.
66
67 Global Height = 0;              ! These are set at runtime.
68 Global Width = 0;
69
70 Global Back_def = 2;            ! Black.
71 Global Fore_def = 9;            ! White.
72
73 Global TopBar = 5;              ! Lines from the top.
74
75 Global player_x = 0;            ! Keeping track of where the player was
76 Global player_y = 0;            !  1 move ago allows us to keep the
77 Global player_x_last = 0;       !  player from walking through obstacles.
78 Global player_y_last = 0;
79
80 Global kitten_x = 0;
81 Global kitten_y = 0;
82 Global kitten_char = 0;
83 Global kitten_color = 0;
84
85 Global last_message = "";       ! Always show the last-encountered message.
86
87 Global nonkitten_count;
88
89 Array nonkitten_x --> Nonkitten_Max;
90 Array nonkitten_y --> Nonkitten_Max;
91 Array nonkitten_color --> Nonkitten_Max;
92 Array nonkitten_char --> Nonkitten_Max;
93 Array nonkitten_msg --> Nonkitten_Max;
94
95 Global already_msg_count = 0;
96 Global already_count = 0;
97 Array already_x --> Nonkitten_Max + 2;
98 Array already_y --> Nonkitten_Max + 2;
99 Array already_msg --> Nonkitten_Max;
100
101 ! If a key is held down while the found_kitten animation is playing,
102 ! (0-->1) & $03ff gets corrupted.  Seems like it might be a bug
103 ! somewhere in Unix Frotz.
104 !
105 Global Real_Release = 0;
106
107 [ Main key;
108         @set_colour Fore_def Back_def;
109
110         if (MESSAGE_NUM < Nonkitten_Default) {
111                 nonkitten_count = MESSAGE_NUM;
112         } else {
113                 nonkitten_count = Nonkitten_Default;
114         }
115
116         Real_Release = (0-->1)&$03ff;
117
118         Width = $21->0;
119         Height = $20->0;
120
121         main_menu();    
122         while (true) {
123                 key = getkey();
124                 switch (key) {
125                 'F':    already_count = 0;
126                         init_nonkittens();
127                         init_kitten();
128                         init_robot();
129                         while (findkitten())
130                                 ;
131                 'D':    set_nonkitten_count();
132                 'I':    print_instructions();
133                 'A':    print_about();
134                 'T':    print_thoughts();
135                 }
136                 if (key == 'Q' || key == $1b)   ! $1b == ESC
137                         break;
138                 main_menu();
139         }
140         quit;
141 ];
142
143
144 [ main_menu psycho;
145
146         ! There's a 1:50 chance that the kitten in the title screen
147         ! will have a "psycho" appearance.
148         !
149         psycho = random(50);
150         if (psycho == 1)
151                 psycho = true;
152         else
153                 psycho = false;
154
155         @erase_window $ffff;
156         @split_window 11;
157         @set_window 1;
158
159         Banner();
160         draw_horiz(TopBar);
161
162         draw_big_robot(3, 7);
163
164         if (psycho)
165                 draw_big_kitten_psycho(14, 7);
166         else
167                 draw_big_kitten(15, 7);
168
169         @set_cursor 7 30;
170         print "http://www.robotfindskitten.org";
171         @set_cursor 8 30;
172         print "Leonard Richardson (C) 1997, 2000";
173         @set_cursor 9 30;
174         print "David Griffith (C) 2002-2019 (Inform Edition)";
175         @set_cursor 10 30;
176         print "    ", MESSAGE_NUM, " different nonkittens!";
177
178         @set_window 0;
179
180         print "  F) Find Kitten^",
181                 "  D) Difficulty  (", nonkitten_count, ")^",
182                 "  I) Instructions^",
183                 "  T) Thoughts^",
184                 "  A) About^",
185                 "  Q) Quit^",
186                 "^> ";
187 ];
188
189
190 ! Copied from module/verblibm.h of the Inform 6.21.3 standard library.
191 !
192 [ Banner i;
193         if (Story ~= 0) {
194                 style bold; 
195                 print (string) Story;
196                 style roman;
197         }
198         if (Headline ~= 0) {
199                 print (string) Headline;
200         }
201         print "Release ", Real_Release, " / Serial number ";
202         for (i=18:i<24:i++) print (char) 0->i;
203         print " / Inform v"; inversion; print "";
204         new_line;
205 ];
206
207
208 Constant INBUFSIZE 80;
209 Array inbuf -> INBUFSIZE;
210
211 [ set_nonkitten_count maxnum val;
212         while (true) {
213                 @erase_window $ffff;
214                 @split_window 5;
215                 @set_window 1;
216                 Banner();
217                 draw_horiz(TopBar);
218                 @set_window 0;
219
220                 if (MESSAGE_NUM < Nonkitten_Max) {
221                         maxnum = MESSAGE_NUM;
222                 } else {
223                         maxnum = Nonkitten_Max;
224                 } 
225
226                 print "^Please enter the number of nonkittens you
227                         wish to search through.^(1 to ", maxnum, " only)^^> ";
228
229                 while (true) {
230                         val = get_number(1, maxnum, nonkitten_count);
231                         if (val == -1) {
232                                 break;
233                         } else {
234                                 nonkitten_count = val;
235                                 return;
236                         }
237                 }
238         }
239 ];
240
241
242 [ get_number min max init inbufvar ix cx len val;
243         while (true) {
244                 inbuf->0 = (INBUFSIZE-3);
245                 inbuf->1 = 0;
246                 inbufvar = inbuf;
247                 ix = 0;
248                 @aread inbufvar ix;
249                 new_line;
250                 len = inbuf->1;
251                 cx = 0;
252                 while (cx < len && inbuf->(2+cx) == ' ')
253                         cx++;
254                 if (cx < len && inbuf->(2+cx) == '.')
255                         break;
256
257                 ! If user just hits return, use what we have already. 
258                 if (len == 0)
259                         return init;
260                 if (cx == len || inbuf->(2+cx) < '0' || inbuf->(2+cx) > '9') {
261                         print "Please enter a value from ", min, " to ", max,
262                                 ", or Enter by itself to exit.^
263                                 [Press any key to continue.] ";
264                         getkey();
265                         return -1;
266                 }
267                 val = 0;
268                 while (cx < len && inbuf->(2+cx) >= '0' && inbuf->(2+cx) <= '9') {
269                         val = val * 10 + (inbuf->(2+cx) - '0');
270                         cx++;
271                 }
272                 if (val < min || val > max) {
273                         print "Please enter a value from ", min, " to ", max,
274                                 ", or Enter by itself to exit.^
275                                 [Press any key to continue.] ";
276                         getkey();
277                         return -1;
278                 } else break;
279         }
280         return val;
281 ];
282
283
284 [ print_about;
285         @erase_window $ffff;
286         @split_window TopBar;
287         @set_window 1;
288         Banner();
289         draw_horiz(TopBar);
290         @set_window 0;
291
292 print "^
293 This Zen simulation is based on the C version v1600003.248b^
294 by Leonard Richardson (C) 1997, 2000.^
295 Written originally for the Nerth Pork robotfindskitten contest.^
296 Reimplemented in Inform by David Griffith (C) 2002.^
297 ^
298 This code is freely redistributable.  Do with it what you will, but
299 don't go about claiming you wrote it.  I, David Griffith, retain
300 copyright on this program except for the NKIs imported from the master
301 (aka POSIX) port.^
302 ^
303 Lots more information on robotfindskitten is available at
304 http://www.robotfindskitten.org.^
305 ^
306 To submit new NKI's, please go to the above URL.^
307 ^
308 ^
309 Release History:^
310 ^
311 Release 1 / Serial number 0211xx to 021214 or so^
312 Initial private release.  Limited distribution for beta testing and
313 debugging purposes.^
314 ^
315 Release 2 / Serial Number 021216^
316 First public release.^
317 ^
318 Release 3 / Serial Number 021221^
319 Bugfix release.^
320 - Movement keys 'J' and 'K' were swapped by mistake.  Fixed.^
321 - Special PalmOS movement key support added.^
322 - More NKIs added (401 total).^
323 ^
324 Release 4 / Serial Number 030131^
325 Light overhaul release.^
326 - Now an official port of robotfindskitten.^
327 - Typos in NKIs fixed.^
328 - Fixed diagonal collision-detection strangeness.^
329 - Added color support.^
330 - Added an easter egg.  Can you find it?^
331 - Removed PalmOS movement key support (superfluous and ugly).^
332 - Removed playfield resizing code (superfluous and ugly).^
333 - It's ~robotfindskitten~, not ~Robot Finds Kitten~.^
334 - Merged in new NKIs from the new POSIX release of robotfindskitten.^
335 - More NKIs added (561 total).^
336 ^
337 Release 5 / Serial Number 030524^
338 Even more NKIs release.^
339 - Idiotic typos fixed.^
340 - More NKIs added (602 total).^
341 ^
342 Release 6 / Serial Number 031116^
343 Challenge release.^
344 - More NKIs added (764 total).^
345 - Increased maximum difficulty to 589.^
346 - Lots more comments in the source code.^
347 - Assorted cleanups in the source code.^
348 ^
349 Release 7 / Serial Number 130320^
350 Modular release.^
351 - Synchronized NKIs and removed redundancies with the POSIX port.^
352 - NKIs now generated from an external file using nki2inf.pl.^
353 - NKIs reduced to 723 because of redundancies and recommended deletions.^
354 ^
355 Release 7 / Serial Number 19xxxx^
356 Another release.^
357 - Fixed a potential problem of wrongly determining screen size.^
358 ^
359 ^
360 Known Bugs:^
361 ^
362 1) I still don't know why already_seen_xy() occasionally causes Robot to
363 get placed on top of another object when a game is started.  Fortunately
364 this seems to happen only very rarely and typically only if the
365 difficulty is set to more than 200.  This bug also seems to very
366 occasionally put Kitten underneath an NKI.^
367 ^
368 2) Under earlier versions of Windows Frotz, Robot used to appear as a
369 solid block. This was because of a bug in Windows Frotz which
370 incorrectly makes the cursor opaque. The cursor is now moved off to
371 the upper-right corner so that the game looks okay on terminals that use
372 something other than reverse for the cursor. I still can't figure out
373 how to make Inform hide the cursor completely. At least on xterm and
374 NetBSD's console, @@64set_cursor -1 doesn't work.^
375 ^
376 3) Under Windows Frotz, an annoying [MORE] prompt might appear at the
377 main menu. This is another bug in Windows Frotz which causes the
378 interpreter to follow Windows' suggestion that something less than 24 or
379 25 lines is okay.^
380 ^
381 [Press any key to continue.] "; 
382         getkey();
383 ];
384
385
386 [ print_instructions;
387         @erase_window $ffff;
388         @split_window TopBar;
389         @set_window 1;
390         Banner();
391         draw_horiz(TopBar);
392         @set_window 0;
393 print "^
394 In this game, you are Robot ( ";
395 style reverse; print "#"; style roman;
396 print " ). Your job is to find Kitten. This task is complicated by the
397 existance of various things which are not Kitten. Robot must touch
398 items to determine if they are Kitten or not.  Move Robot with the
399 cursor keys, the numeric keypad (make sure numlock is on), or using the
400 vi/rogue/nethack movement keys. The game ends when robotfindskitten.
401 Alternatively, you may end the game by hitting the Esc or Q keys.^
402 ^
403 [Press any key to continue.] "; 
404         getkey();
405 ];
406
407
408 [ print_thoughts;
409         @erase_window $ffff;
410         @split_window TopBar;
411         @set_window 1;
412         Banner();
413         draw_horiz(TopBar);
414         @set_window 0;
415 print "^
416 A Final Thought.^
417 ^
418 Day and night I feverishly worked upon the machine, creating both a soul
419 which could desire its goal, and a body with which it could realize 
420 it. Many who saw my creation called it an abomination, and denied me
421 grant money.  But they could not dissuade me from my impossible 
422 task.  It was a spectre that tormented me always, a ghost I had to give
423 a form and a life, lest it consume me from the inside.  And when at last
424 my task was done, when the grey box on wheels was complete and when it,
425 as well as I, knew what had to be done, I felt deep sympathy for the
426 machine.  For I had not destroyed the phantom, but merely exorcized it
427 into another body.  The robot knew not why this task had to be
428 performed, for I could not imbue it with knowledge I did not myself
429 posess.  And at the same time, I felt a sweeping sense of relief sweep
430 over me, that somehow, the dream that had driven me for my entire life
431 had come one step closer to fruition.^
432 ^
433 ~Gort, Klaatu Verada Nikto~^
434 ^
435 As I vocally activated the robot, I realized that it was following my
436 instructions, but not out of any desire to obey me.  Had I remained
437 silent, it would have performed exactly the same operations.  We were
438 two beings controlled by the same force now.  And yet, seeking vainly to
439 hold some illusion of control over the machine I thought I had created,
440 I gave my final command.^
441 ^
442 ~GO!~  I told the box as it began to roll out of my workshop into the
443 frozen desert beyond. ~FIND KITTEN!~^
444 ^
445 -- The Book of Found Kittens, pages 43-4, author unknown.^
446 ^
447 [Press any key to continue.] "; 
448         getkey();
449 ];
450
451
452 [ draw_big_robot x y; 
453         if (x == 0)
454                 x = 1;
455         if (y == 0)
456                 y = 1;
457         @set_cursor y x;
458         @set_colour 6 Back_def;
459         print "[";
460         @set_colour 4 Back_def;
461         print "-";
462         @set_colour 6 Back_def;
463         print "]";
464
465         y = y+1;
466         @set_cursor y x;
467         @set_colour 6 Back_def;
468         print "(";
469         @set_colour 3 Back_def;
470         print "+";
471         @set_colour 6 Back_def;
472         print ")";
473         @set_colour 8 Back_def;
474         print "=C";
475
476         y = y+1;
477         @set_cursor y x;
478         @set_colour 6 Back_def;
479         print "| |";
480
481         y = y+1;
482         @set_cursor y x;
483         @set_colour 8 Back_def;
484         print "OOO";
485
486         @set_colour Fore_def Back_def;
487 ];
488
489
490 [ draw_big_kitten x y;
491         if (x == 0)
492                 x = 1;
493         if (y == 0)
494                 y = 1;
495         @set_cursor y x;
496
497         @set_colour 5 Back_def;
498         print "|", (char) 92, "_/|";
499         y++;
500         @set_cursor y x;
501         print "|";
502         @set_colour 4 Back_def;
503         print "o o";
504         @set_colour 5 Back_def;
505         print "|__";
506         y++;
507         @set_cursor y x;
508         @set_colour 9 Back_def;
509         print "--";
510         @set_colour 3 Back_def;
511         print "*";
512         @set_colour 9 Back_def;
513         print "--";
514         @set_colour 5 Back_def;
515         print "__", (char) 92;
516         y++;
517         @set_cursor y x;
518         print "C_C(____)";      
519
520         @set_colour Fore_def Back_def;
521 ];
522
523
524 [ draw_big_kitten_psycho x y;
525         if (x == 0)
526                 x = 1;
527         if (y == 0)
528                 y = 1;
529         @set_cursor y x;
530
531         @set_colour 5 Back_def;
532         print " |", (char) 92, "_/|";
533         y++;
534         @set_cursor y x;
535         @set_colour 4 Back_def;
536         print "(|) (|)";
537         @set_colour 5 Back_def;
538         print "_";
539         y++;
540         @set_cursor y x;
541         @set_colour 9 Back_def;
542         print " --";
543         @set_colour 3 Back_def;
544         print "O";
545         @set_colour 9 Back_def;
546         print "--";
547         @set_colour 5 Back_def;
548         print "__", (char) 92;
549         y++;
550         @set_cursor y x;
551         print " 3_3(____)";     
552
553         @set_colour Fore_def Back_def;
554 ];
555
556
557 ! Something gets messed up if I make this local to findkitten()
558 ! When going right or left, then up or down to hit the Kitten, the
559 ! animation gets reversed.
560
561 Global last_right = false;
562
563 [ findkitten key i;
564         @erase_window $ffff;
565         @split_window TopBar;
566         @set_window 1;
567         @set_cursor 1 1;
568
569         Banner();
570         print (string) last_message;
571         draw_horiz(TopBar);
572
573         draw_object(kitten_x, kitten_y, kitten_char, kitten_color);
574         draw_nonkittens();
575
576         style reverse;
577         draw_object(player_x, player_y, '#');
578         style roman;
579
580         @set_cursor 1 Width;
581
582         ! Get movement key
583         !
584         key = getkey();
585
586         ! Move Robot
587         !
588         player_x_last = player_x;
589         player_y_last = player_y;
590         switch (key) {
591         'Q', $1b:       rfalse;                 ! exit game ($1b == Esc)
592         '8', 'K', 129:  player_y--;             ! up
593         '2', 'J', 130:  player_y++;             ! down
594         '4', 'H', 131:  player_x--;             ! left
595                         last_right = false;
596         '6', 'L', 132:  player_x++;             ! right
597                         last_right = true;
598
599         '7', 'Y':       player_y--; player_x--; ! up-left
600                         last_right = false;
601         '9', 'U':       player_y--; player_x++; ! up-right
602                         last_right = true;
603         '1', 'B':       player_y++; player_x--; ! down-left
604                         last_right = false;
605         '3', 'N':       player_y++; player_x++; ! down-right
606                         last_right = true;
607         }
608
609         ! Keep Robot from falling off edges of playfield.
610         !
611         if (player_y == TopBar || player_y > Height) {
612                 player_y = player_y_last;
613         }
614         if (player_x < 1 || player_x > Width) {
615                 player_x = player_x_last;
616         }
617
618         ! Detect and handle collisions.
619         !
620         if (player_x == kitten_x && player_y == kitten_y) {
621                 animate_kitten(key, last_right);
622                 getkey();
623                 rfalse;
624         }
625         for (i = 0: i < nonkitten_count: i++) {
626                 if (player_x == nonkitten_x-->i
627                 && player_y == nonkitten_y-->i) {
628                         @set_cursor 1 1;
629                         last_message = lookup_msg(nonkitten_msg-->i);
630                         player_x = player_x_last;
631                         player_y = player_y_last;
632                 }
633         }
634         rtrue;
635 ];
636
637
638 [ animate_kitten key my_last_right i j junk robot_x anim_finished;
639         switch (key) {
640         '8', 'J', 129:  player_y++;
641         '2', 'K', 130:  player_y--;
642         '4', 'H', 131:  player_x++;
643         '6', 'L', 132:  player_x--;
644         '7', 'Y':       player_y++; player_x++; 
645         '9', 'U':       player_y++; player_x--;
646         '1', 'B':       player_y--; player_x++;
647         '3', 'N':       player_y--; player_x--;
648         }
649
650         anim_finished = false;
651         for (i = 4: i >= 0: i--) {
652                 @erase_window $ffff;
653                 @split_window TopBar;
654                 @set_window 1;
655                 @set_cursor 1 1;
656
657                 Banner();
658                 draw_horiz(TopBar);
659
660                 if (i > 0) {
661                         if (my_last_right) {
662                                 robot_x = Anim_Meet - i;
663                                 style reverse;
664                                 draw_object(robot_x, TopBar - 1, '#');
665                                 style roman;
666                                 draw_object(Anim_Meet - 1 + i, TopBar - 1, 
667                                         kitten_char, kitten_color);
668                         } else {
669                                 robot_x = Anim_Meet - 1 + i;
670                                 style reverse;
671                                 draw_object(robot_x, TopBar - 1, '#');
672                                 style roman;
673                                 draw_object(Anim_Meet - i, TopBar - 1,
674                                         kitten_char, kitten_color);
675                         }
676                 } else {
677                         j = TopBar - 1;
678                         @set_cursor j 1;
679                         print "You found Kitten!  Way to go, Robot!";
680                         anim_finished = true;
681                 }
682
683                 draw_object(kitten_x, kitten_y, kitten_char, kitten_color);
684
685                 style reverse;
686                 draw_object(player_x, player_y, '#');
687                 style roman;
688                 draw_nonkittens();
689
690                 if (anim_finished == false) {
691                         j = TopBar - 1;
692                         @set_cursor 1 Width;
693                         @aread junk 0 10 pause -> junk;
694                 } else {
695                         style reverse;
696                         draw_object(player_x, player_y, '#');
697                         style roman;
698                         @set_cursor 1 Width;
699                 }
700         }
701 ];
702
703
704 [ already_seen_xy x y i;
705         for (i = 0: i < already_count: i++) {
706                 if (already_x-->already_count == x &&
707                 already_y-->already_count ==y) {
708                         rtrue;
709                 }
710         }
711         already_x-->already_count = x;
712         already_y-->already_count = y;
713         already_count++;
714         rfalse;
715 ];
716
717
718 [ pause;
719         rtrue;
720 ];
721
722
723 [ init_kitten;
724         kitten_x = get_random_x();
725         kitten_y = get_random_y();
726         kitten_color = get_random_color();
727         while (already_seen_xy(kitten_x, kitten_y) == true) {
728                 kitten_x = get_random_x();
729                 kitten_y = get_random_y();
730         }
731         kitten_char = get_random_char();
732 ];
733
734
735 [ init_robot;
736         player_x = get_random_x();
737         player_y = get_random_y();
738         while (already_seen_xy(player_x, player_y) == true) {
739                 player_x = get_random_x();
740                 player_y = get_random_y();
741         }
742 ];      
743
744
745 [ init_nonkittens i;
746         already_msg_count = 0;
747         last_message = "";
748         for (i = 0: i < nonkitten_count: i++) {
749                 nonkitten_x-->i = get_random_x();
750                 nonkitten_y-->i = get_random_y();
751                 nonkitten_color-->i = get_random_color();
752                 while (already_seen_xy(nonkitten_x-->i, 
753                         nonkitten_y-->i) == true) {
754                         nonkitten_x-->i = get_random_x();
755                         nonkitten_y-->i = get_random_y();
756                 }
757                 nonkitten_char-->i = get_random_char();
758                 nonkitten_msg-->i = get_random_msg();
759         }
760 ];
761
762
763 [ draw_nonkittens i;
764         for (i = 0: i < nonkitten_count: i++) {
765                 draw_object(nonkitten_x-->i,
766                                 nonkitten_y-->i,
767                                 nonkitten_char-->i,
768                                 nonkitten_color-->i);
769         }
770 ];
771
772
773 [ draw_object x y character fore back;
774         @set_cursor y x;
775
776         if (fore == "")
777                 fore = Back_def;
778         if (back == "")
779                 back = Back_def;        
780
781         @set_colour fore Back_def;
782         if (character)
783                 print (char) character;
784
785         @set_colour Fore_def Back_def;
786 ];
787
788
789 [ draw_horiz row i;
790         @set_cursor row 1;
791         for (i = 0 : i < Width : i++)
792                 print (char) '-';
793 ];
794
795
796 [ getkey x;
797         @read_char 1 -> x;
798         if (x >= 'a' && x <= 'z')
799                 x = x - ('a' - 'A');
800         return x;
801 ];
802
803
804 [ get_random_char num;
805         num = random(93);
806         num = num + 33;
807         while (num == 35) {             ! avoid choosing '#'
808                 num = random(93);
809                 num = num + 33;
810         }
811         return num;
812 ];
813
814
815 [ get_random_msg num;
816         num = random(MESSAGE_NUM);
817         while (is_duplicate_msg(num) == true) {
818                 num = random(MESSAGE_NUM);
819         }
820         return num;
821 ];
822
823
824 [ get_random_color num;
825         num = random(7) + 2;
826         ! 0 and 1 are default color and current color
827         ! and we want to avoid picking the default color explicitly
828         while (num == $2c-->0) {
829                 num = random(7) + 2;
830         }
831         return num;
832 ];
833
834
835 [ is_duplicate_msg num i;
836         for (i = 0: i < already_msg_count: i++) {
837                 if (already_msg-->i==num) {
838                         rtrue;
839                 }
840         }
841         already_msg-->already_msg_count = num;
842         already_msg_count++;
843         rfalse;
844 ];
845
846
847 [ get_random_x;
848         ! Maybe this will need to do something more in the future.
849         return random(Width);
850 ];
851
852
853 [ get_random_y num;
854         ! Make sure we don't draw in the status bar.
855         while (true) {
856                 num = random(Height);
857                 if (num > TopBar)
858                         return num;
859         }
860 ];
861