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