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