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