New NKIs!
[rfk-inform.git] / kitten.inf
1 ! robotfindskitten
2 ! A Zen Simulation
3 ! Release 8 / Serial number 220120 / Inform v6.35
4 !
5 !     [-]       |\_/|        http://www.robotfindskitten.org
6 !     (+)=C     |o o|__      Leonard Richardson (C) 1997, 2000
7 !     | |       --*--__\     David Griffith (C) 2002-2022  (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 "220120";
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-2022 (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 220120^
358 - Twenty Year Anniversary release.^
359 - Fixed a problem that crashed some interpreters when robotfindskitten.^
360 - Fixed a potential problem of wrongly determining screen size.^
361 - Now distributed under the Artistic License 2.0.^
362 ^
363 ^
364 Known Bugs:^
365 ^
366 1) I still don't know why already_seen_xy() occasionally causes Robot to
367 get placed on top of another object when a game is started.  Fortunately
368 this seems to happen only very rarely and typically only if the
369 difficulty is set to more than 200.  This bug also seems to very
370 occasionally put Kitten underneath an NKI.^
371 ^
372 2) Under earlier versions of Windows Frotz, Robot used to appear as a
373 solid block. This was because of a bug in Windows Frotz which
374 incorrectly makes the cursor opaque. The cursor is now moved off to
375 the upper-right corner so that the game looks okay on terminals that use
376 something other than reverse for the cursor. I still can't figure out
377 how to make Inform hide the cursor completely. At least on xterm and
378 NetBSD's console, @@64set_cursor -1 doesn't work.^
379 ^
380 3) Under Windows Frotz, an annoying [MORE] prompt might appear at the
381 main menu. This is another bug in Windows Frotz which causes the
382 interpreter to follow Windows' suggestion that something less than 24 or
383 25 lines is okay.^
384 ^
385 [Press any key to continue.] "; 
386         getkey();
387 ];
388
389
390 [ print_instructions;
391         @erase_window $ffff;
392         @split_window TopBar;
393         @set_window 1;
394         Banner();
395         draw_horiz(TopBar);
396         @set_window 0;
397 print "^
398 In this game, you are Robot ( ";
399 style reverse; print "#"; style roman;
400 print " ). Your job is to find Kitten. This task is complicated by the
401 existance of various things which are not Kitten. Robot must touch
402 items to determine if they are Kitten or not.  Move Robot with the
403 cursor keys, the numeric keypad (make sure numlock is on), or using the
404 vi/rogue/nethack movement keys. The game ends when robotfindskitten.
405 Alternatively, you may end the game by hitting the Esc or Q keys.^
406 ^
407 [Press any key to continue.] "; 
408         getkey();
409 ];
410
411
412 [ print_thoughts;
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         if (x == 0)
458                 x = 1;
459         if (y == 0)
460                 y = 1;
461         @set_cursor y x;
462         @set_colour 6 Back_def;
463         print "[";
464         @set_colour 4 Back_def;
465         print "-";
466         @set_colour 6 Back_def;
467         print "]";
468
469         y = y+1;
470         @set_cursor y x;
471         @set_colour 6 Back_def;
472         print "(";
473         @set_colour 3 Back_def;
474         print "+";
475         @set_colour 6 Back_def;
476         print ")";
477         @set_colour 8 Back_def;
478         print "=C";
479
480         y = y+1;
481         @set_cursor y x;
482         @set_colour 6 Back_def;
483         print "| |";
484
485         y = y+1;
486         @set_cursor y x;
487         @set_colour 8 Back_def;
488         print "OOO";
489
490         @set_colour Fore_def Back_def;
491 ];
492
493
494 [ draw_big_kitten x y;
495         if (x == 0)
496                 x = 1;
497         if (y == 0)
498                 y = 1;
499         @set_cursor y x;
500
501         @set_colour 5 Back_def;
502         print "|", (char) 92, "_/|";
503         y++;
504         @set_cursor y x;
505         print "|";
506         @set_colour 4 Back_def;
507         print "o o";
508         @set_colour 5 Back_def;
509         print "|__";
510         y++;
511         @set_cursor y x;
512         @set_colour 9 Back_def;
513         print "--";
514         @set_colour 3 Back_def;
515         print "*";
516         @set_colour 9 Back_def;
517         print "--";
518         @set_colour 5 Back_def;
519         print "__", (char) 92;
520         y++;
521         @set_cursor y x;
522         print "C_C(____)";      
523
524         @set_colour Fore_def Back_def;
525 ];
526
527
528 [ draw_big_kitten_psycho x y;
529         if (x == 0)
530                 x = 1;
531         if (y == 0)
532                 y = 1;
533         @set_cursor y x;
534
535         @set_colour 5 Back_def;
536         print " |", (char) 92, "_/|";
537         y++;
538         @set_cursor y x;
539         @set_colour 4 Back_def;
540         print "(|) (|)";
541         @set_colour 5 Back_def;
542         print "_";
543         y++;
544         @set_cursor y x;
545         @set_colour 9 Back_def;
546         print " --";
547         @set_colour 3 Back_def;
548         print "O";
549         @set_colour 9 Back_def;
550         print "--";
551         @set_colour 5 Back_def;
552         print "__", (char) 92;
553         y++;
554         @set_cursor y x;
555         print " 3_3(____)";     
556
557         @set_colour Fore_def Back_def;
558 ];
559
560
561 ! Something gets messed up if I make this local to findkitten()
562 ! When going right or left, then up or down to hit the Kitten, the
563 ! animation gets reversed.
564
565 Global last_right = false;
566
567 [ findkitten key i;
568         @erase_window $ffff;
569         @split_window TopBar;
570         @set_window 1;
571         @set_cursor 1 1;
572
573         Banner();
574         print (string) last_message;
575         draw_horiz(TopBar);
576
577         draw_object(kitten_x, kitten_y, kitten_char, kitten_color);
578         draw_nonkittens();
579
580         style reverse;
581         draw_object(player_x, player_y, '#');
582         style roman;
583
584         @set_cursor 1 Width;
585
586         ! Get movement key
587         !
588         key = getkey();
589
590         ! Move Robot
591         !
592         player_x_last = player_x;
593         player_y_last = player_y;
594         switch (key) {
595         'Q', $1b:       rfalse;                 ! exit game ($1b == Esc)
596         '8', 'K', 129:  player_y--;             ! up
597         '2', 'J', 130:  player_y++;             ! down
598         '4', 'H', 131:  player_x--;             ! left
599                         last_right = false;
600         '6', 'L', 132:  player_x++;             ! right
601                         last_right = true;
602
603         '7', 'Y':       player_y--; player_x--; ! up-left
604                         last_right = false;
605         '9', 'U':       player_y--; player_x++; ! up-right
606                         last_right = true;
607         '1', 'B':       player_y++; player_x--; ! down-left
608                         last_right = false;
609         '3', 'N':       player_y++; player_x++; ! down-right
610                         last_right = true;
611         }
612
613         ! Keep Robot from falling off edges of playfield.
614         !
615         if (player_y == TopBar || player_y > Height) {
616                 player_y = player_y_last;
617         }
618         if (player_x < 1 || player_x > Width) {
619                 player_x = player_x_last;
620         }
621
622         ! Detect and handle collisions.
623         !
624         if (player_x == kitten_x && player_y == kitten_y) {
625                 animate_kitten(key, last_right);
626                 getkey();
627                 rfalse;
628         }
629         for (i = 0: i < nonkitten_count: i++) {
630                 if (player_x == nonkitten_x-->i
631                 && player_y == nonkitten_y-->i) {
632                         @set_cursor 1 1;
633                         last_message = lookup_msg(nonkitten_msg-->i);
634                         player_x = player_x_last;
635                         player_y = player_y_last;
636                 }
637         }
638         rtrue;
639 ];
640
641
642 [ animate_kitten key my_last_right i j junk robot_x anim_finished;
643         switch (key) {
644         '8', 'J', 129:  player_y++;
645         '2', 'K', 130:  player_y--;
646         '4', 'H', 131:  player_x++;
647         '6', 'L', 132:  player_x--;
648         '7', 'Y':       player_y++; player_x++; 
649         '9', 'U':       player_y++; player_x--;
650         '1', 'B':       player_y--; player_x++;
651         '3', 'N':       player_y--; player_x--;
652         }
653
654         anim_finished = false;
655         for (i = 4: i >= 0: i--) {
656                 @erase_window $ffff;
657                 @split_window TopBar;
658                 @set_window 1;
659                 @set_cursor 1 1;
660
661                 Banner();
662                 draw_horiz(TopBar);
663
664                 if (i > 0) {
665                         if (my_last_right) {
666                                 robot_x = Anim_Meet - i;
667                                 style reverse;
668                                 draw_object(robot_x, TopBar - 1, '#');
669                                 style roman;
670                                 draw_object(Anim_Meet - 1 + i, TopBar - 1, 
671                                         kitten_char, kitten_color);
672                         } else {
673                                 robot_x = Anim_Meet - 1 + i;
674                                 style reverse;
675                                 draw_object(robot_x, TopBar - 1, '#');
676                                 style roman;
677                                 draw_object(Anim_Meet - i, TopBar - 1,
678                                         kitten_char, kitten_color);
679                         }
680                 } else {
681                         j = TopBar - 1;
682                         @set_cursor j 1;
683                         print "You found Kitten!  Way to go, Robot!";
684                         anim_finished = true;
685                 }
686
687                 draw_object(kitten_x, kitten_y, kitten_char, kitten_color);
688
689                 style reverse;
690                 draw_object(player_x, player_y, '#');
691                 style roman;
692                 draw_nonkittens();
693
694                 if (anim_finished == false) {
695                         j = TopBar - 1;
696                         @set_cursor 1 Width;
697                         @read_char 1 10 pause -> junk;
698                         @nop;   ! This is for padding.
699                 } else {
700                         style reverse;
701                         draw_object(player_x, player_y, '#');
702                         style roman;
703                         @set_cursor 1 Width;
704                 }
705         }
706 ];
707
708
709 [ already_seen_xy x y i;
710         for (i = 0: i < already_count: i++) {
711                 if (already_x-->already_count == x &&
712                 already_y-->already_count ==y) {
713                         rtrue;
714                 }
715         }
716         already_x-->already_count = x;
717         already_y-->already_count = y;
718         already_count++;
719         rfalse;
720 ];
721
722
723 [ pause;
724         rtrue;
725 ];
726
727
728 [ init_kitten;
729         kitten_x = get_random_x();
730         kitten_y = get_random_y();
731         kitten_color = get_random_color();
732         while (already_seen_xy(kitten_x, kitten_y) == true) {
733                 kitten_x = get_random_x();
734                 kitten_y = get_random_y();
735         }
736         kitten_char = get_random_char();
737 ];
738
739
740 [ init_robot;
741         player_x = get_random_x();
742         player_y = get_random_y();
743         while (already_seen_xy(player_x, player_y) == true) {
744                 player_x = get_random_x();
745                 player_y = get_random_y();
746         }
747 ];      
748
749
750 [ init_nonkittens i;
751         already_msg_count = 0;
752         last_message = "";
753         for (i = 0: i < nonkitten_count: i++) {
754                 nonkitten_x-->i = get_random_x();
755                 nonkitten_y-->i = get_random_y();
756                 nonkitten_color-->i = get_random_color();
757                 while (already_seen_xy(nonkitten_x-->i, 
758                         nonkitten_y-->i) == true) {
759                         nonkitten_x-->i = get_random_x();
760                         nonkitten_y-->i = get_random_y();
761                 }
762                 nonkitten_char-->i = get_random_char();
763                 nonkitten_msg-->i = get_random_msg();
764         }
765 ];
766
767
768 [ draw_nonkittens i;
769         for (i = 0: i < nonkitten_count: i++) {
770                 draw_object(nonkitten_x-->i,
771                                 nonkitten_y-->i,
772                                 nonkitten_char-->i,
773                                 nonkitten_color-->i);
774         }
775 ];
776
777
778 [ draw_object x y character fore back;
779         @set_cursor y x;
780
781         if (fore == "")
782                 fore = Back_def;
783         if (back == "")
784                 back = Back_def;        
785
786         @set_colour fore Back_def;
787         if (character)
788                 print (char) character;
789
790         @set_colour Fore_def Back_def;
791 ];
792
793
794 [ draw_horiz row i;
795         @set_cursor row 1;
796         for (i = 0 : i < Width : i++)
797                 print (char) '-';
798 ];
799
800
801 [ getkey x;
802         @read_char 1 -> x;
803         if (x >= 'a' && x <= 'z')
804                 x = x - ('a' - 'A');
805         return x;
806 ];
807
808
809 [ get_random_char num;
810         num = random(93);
811         num = num + 33;
812         while (num == 35) {             ! avoid choosing '#'
813                 num = random(93);
814                 num = num + 33;
815         }
816         return num;
817 ];
818
819
820 [ get_random_msg num;
821         num = random(MESSAGE_NUM);
822         while (is_duplicate_msg(num) == true || num > MESSAGE_NUM || num < 1) {
823                 num = random(MESSAGE_NUM);
824         }
825         return num;
826 ];
827
828
829 [ get_random_color num;
830         num = random(7) + 2;
831         ! 0 and 1 are default color and current color
832         ! and we want to avoid picking the default color explicitly
833         while (num == $2c-->0) {
834                 num = random(7) + 2;
835         }
836         return num;
837 ];
838
839
840 [ is_duplicate_msg num i;
841         for (i = 0: i < already_msg_count: i++) {
842                 if (already_msg-->i==num) {
843                         rtrue;
844                 }
845         }
846         already_msg-->already_msg_count = num;
847         already_msg_count++;
848         rfalse;
849 ];
850
851
852 [ get_random_x;
853         ! Maybe this will need to do something more in the future.
854         return random(Width);
855 ];
856
857
858 [ get_random_y num;
859         ! Make sure we don't draw in the status bar.
860         while (true) {
861                 num = random(Height);
862                 if (num > TopBar)
863                         return num;
864         }
865 ];
866