name in canonical form
[rfk] / rfk.c
1 /*  robotfindskitten for maemo
2  *  original by Leonard Richardson, 1997
3  *  ported to maemo by Thomas Thurman, 2009
4  *  suggestions welcome
5  *  Compile with:
6  *  gcc -Wall -g rfk.c -o rfk `pkg-config --cflags --libs gtk+-2.0 hildon-1`
7  */
8
9 #include <gtk/gtk.h>
10 #include <stdlib.h>
11 #include <glib.h>
12 #include <hildon/hildon.h>
13 #include <math.h>
14
15 #define ARENA_WIDTH 25
16 #define ARENA_HEIGHT 12
17
18 const int amount_of_random_stuff = 15;
19
20 const char *explanation =
21   "In this game, you are robot (#). "
22   "Your job is to find kitten. This task is complicated "
23   "by the existence of various things which are not kitten. "
24   "Robot must touch items to determine if they are kitten or "
25   "not. The game ends when robotfindskitten. You may move "
26   "robot about by tapping on any side of robot, or with the "
27   "cursor keys.";
28
29 static char* messages[] =
30   {
31     "\"I pity the fool who mistakes me for kitten!\", sez Mr. T.",
32     "That's just an old tin can.",
33     "It's an altar to the horse god.",
34     "A box of dancing mechanical pencils. They dance! They sing!",
35     "It's an old Duke Ellington record.",
36     "A box of fumigation pellets.",
37     "A digital clock. It's stuck at 2:17 PM.",
38     "That's just a charred human corpse.",
39     "I don't know what that is, but it's not kitten.",
40     "An empty shopping bag. Paper or plastic?",
41     "Could it be... a big ugly bowling trophy?",
42     "A coat hanger hovers in thin air. Odd.",
43     "Not kitten, just a packet of Kool-Aid(tm).",
44     "A freshly-baked pumpkin pie.",
45     "A lone, forgotten comma, sits here, sobbing.",
46     "ONE HUNDRED THOUSAND CARPET FIBERS!!!!!",
47     "It's Richard Nixon's nose!",
48     "It's Lucy Ricardo. \"Aaaah, Ricky!\", she says.",
49     "You stumble upon Bill Gates' stand-up act.",
50     "Just an autographed copy of the Kama Sutra.",
51     "It's the Will Rogers Highway. Who was Will Rogers, anyway?",
52     "It's another robot, more advanced in design than you but strangely immobile.",
53     "Leonard Richardson is here, asking people to lick him.",
54     "It's a stupid mask, fashioned after a beagle.",
55     "Your State Farm Insurance(tm) representative!",
56     "It's the local draft board.",
57     "Seven 1/4\" screws and a piece of plastic.",
58     "An 80286 machine.",
59     "One of those stupid \"Homes of the Stars\" maps.",
60     "A signpost saying \"TO KITTEN\". It points in no particular direction.",
61     "A hammock stretched between a tree and a volleyball pole.",
62     "A Texas Instruments of Destruction calculator.",
63     "It's a dark, amphorous blob of matter.",
64     "Just a pincushion.",
65     "It's a mighty zombie talking about some love and prosperity.",
66     "\"Dear robot, you may have already won our 10 MILLION DOLLAR prize...\"",
67     "It's just an object.",
68     "A mere collection of pixels.",
69     "A badly dented high-hat cymbal lies on its side here.",
70     "A marijuana brownie.",
71     "A plush Chewbacca.",
72     "Daily hunger conditioner from Australasia",
73     "Just some stuff.",
74     "Why are you touching this when you should be finding kitten?",
75     "A glorious fan of peacock feathers.",
76     "It's some compromising photos of Babar the Elephant.",
77     "A copy of the Weekly World News. Watch out for the chambered nautilus!",
78     "It's the proverbial wet blanket.",
79     "A \"Get Out of Jail Free\" card.",
80     "An incredibly expensive \"Mad About You\" collector plate.",
81     "Paul Moyer's necktie.",
82     "A haircut and a real job. Now you know where to get one!",
83     "An automated robot-hater. It frowns disapprovingly at you.",
84     "An automated robot-liker. It smiles at you.",
85     "It's a black hole. Don't fall in!",
86     "Just a big brick wall.",
87     "You found kitten! No, just kidding.",
88     "Heart of Darkness brand pistachio nuts.",
89     "A smoking branding iron shaped like a 24-pin connector.",
90     "It's a Java applet.",
91     "An abandoned used-car lot.",
92     "A shameless plug for Maemo.",
93     "A shameless plug for the UCLA Linux Users Group: http://linux.ucla.edu/",
94     "A can of Spam Lite.",
95     "This is another fine mess you've gotten us into, Stanley.",
96     "It's scenery for \"Waiting for Godot\".",
97     "This grain elevator towers high above you.",
98     "A Mentos wrapper.",
99     "It's the constellation Pisces.",
100     "It's a fly on the wall. Hi, fly!",
101     "This kind of looks like kitten, but it's not.",
102     "It's a banana! Oh, joy!",
103     "A helicopter has crashed here.",
104     "Carlos Tarango stands here, doing his best impression of Pat Smear.",
105     "A patch of mushrooms grows here.",
106     "A patch of grape jelly grows here.",
107     "A spindle, and a grindle, and a bucka-wacka-woom!",
108     "A geyser sprays water high into the air.",
109     "A toenail? What good is a toenail?",
110     "You've found the fish! Not that it does you much good in this game.",
111     "A Buttertonsils bar.",
112     "One of the few remaining discoes.",
113     "Ah, the uniform of a Revolutionary-era minuteman.",
114     "A punch bowl, filled with punch and lemon slices.",
115     "It's nothing but a G-thang, baby.",
116     "IT'S ALIVE! AH HA HA HA HA!",
117     "This was no boating accident!",
118     "Wait! This isn't the poker chip! You've been tricked! DAMN YOU, MENDEZ!",
119     "A livery stable! Get your livery!",
120     "It's a perpetual immobility machine.",
121     "\"On this spot in 1962, Henry Winkler was sick.\"",
122     "There's nothing here; it's just an optical illusion.",
123     "The World's Biggest Motzah Ball!",
124     "A tribe of cannibals lives here. They eat Malt-O-Meal for breakfast, you know.",
125     "This appears to be a rather large stack of trashy romance novels.",
126     "Look out! Exclamation points!",
127     "A herd of wild coffee mugs slumbers here.",
128     "It's a limbo bar! How low can you go?",
129     "It's the horizon. Now THAT'S weird.",
130     "A vase full of artificial flowers is stuck to the floor here.",
131     "A large snake bars your way.",
132     "A pair of saloon-style doors swing slowly back and forth here.",
133     "It's an ordinary bust of Beethoven... but why is it painted green?",
134     "It's TV's lovable wisecracking Crow! \"Bite me!\", he says.",
135     "Hey, look, it's war. What is it good for? Absolutely nothing. Say it again.",
136     "It's the amazing self-referential thing that's not kitten.",
137     "A flamboyant feather boa. Now you can dress up like Carol Channing!",
138     "\"Sure hope we get some rain soon,\" says Farmer Joe.",
139     "\"How in heck can I wash my neck if it ain't gonna rain no more?\" asks Farmer Al.",
140     "\"Topsoil's all gone, ma,\" weeps Lil' Greg.",
141     "This is a large brown bear. Oddly enough, it's currently peeing in the woods.",
142     "A team of arctic explorers is camped here.",
143     "This object here appears to be Louis Farrakhan's bow tie.",
144     "This is the world-famous Chain of Jockstraps.",
145     "A trash compactor, compacting away.",
146     "This toaster strudel is riddled with bullet holes!",
147     "It's a hologram of a crashed helicopter.",
148     "This is a television. On screen you see a robot strangely similar to yourself.",
149     "This balogna has a first name, it's R-A-N-C-I-D.",
150     "A salmon hatchery? Look again. It's merely a single salmon.",
151     "It's a rim shot. Ba-da-boom!",
152     "It's creepy and it's kooky, mysterious and spooky. It's also somewhat ooky.",
153     "This is an anagram.",
154     "This object is like an analogy.",
155     "It's a symbol. You see in it a model for all symbols everywhere.",
156     "The object pushes back at you.",
157     "A traffic signal. It appears to have been recently vandalized.",
158     "\"There is no kitten!\" cackles the old crone. You are shocked by her blasphemy.",
159     "This is a Lagrange point. Don't come too close now.",
160     "The dirty old tramp bemoans the loss of his harmonica.",
161     "Look, it's Fanny the Irishman!",
162     "What in blazes is this?",
163     "It's the instruction manual for a previous version of this game.",
164     "A brain cell. Oddly enough, it seems to be functioning.",
165     "Tea and/or crumpets.",
166     "This jukebox has nothing but Cliff Richards albums in it.",
167     "It's a Quaker Oatmeal tube, converted into a drum.",
168     "This is a remote control. Being a robot, you keep a wide berth.",
169     "It's a roll of industrial-strength copper wire.",
170     "Oh boy! Grub! Er, grubs.",
171     "A puddle of mud, where the mudskippers play.",
172     "Plenty of nothing.",
173     "Look at that, it's the Crudmobile.",
174     "Just Walter Mattheau and Jack Lemmon.",
175     "Two crepes, two crepes in a box.",
176     "An autographed copy of \"Primary Colors\", by Anonymous.",
177     "Another rabbit? That's three today!",
178     "It's a segmentation fault. Core dumped, by the way.",
179     "A historical marker showing the actual location of /dev/null.",
180     "Thar's Mobius Dick, the convoluted whale. Arrr!",
181     "It's a charcoal briquette, smoking away.",
182     "A pizza, melting in the sun.",
183     "It's a \"HOME ALONE 2: Lost in New York\" novelty cup.",
184     "A stack of 7 inch floppies wobbles precariously.",
185     "It's nothing but a corrupted floppy. Coaster anyone?",
186     "A section of glowing phosphor cells sings a song of radiation to you.",
187     "This TRS-80 III is eerily silent.",
188     "A toilet bowl occupies this space.",
189     "This peg-leg is stuck in a knothole!",
190     "It's a solitary vaccuum tube.",
191     "This corroded robot is clutching a mitten.",
192     "\"Hi, I'm Anson Williams, TV's 'Potsy'.\"",
193     "This subwoofer was blown out in 1974.",
194     "Three half-pennies and a wooden nickel.",
195     "It's the missing chapter to \"A Clockwork Orange\".",
196     "It's a burrito stand flyer. \"Taqueria El Ranchito\".",
197     "This smiling family is happy because they eat LARD.",
198     "Roger Avery, persona un famoso de los Estados Unidos.",
199     "Ne'er but a potted plant.",
200     "A parrot, kipping on its back.",
201     "A forgotten telephone switchboard.",
202     "A forgotten telephone switchboard operator.",
203     "It's an automated robot-disdainer. It pretends you're not there.",
204     "It's a portable hole. A sign reads: \"Closed for the winter\".",
205     "Just a moldy loaf of bread.",
206     "A little glass tub of Carmex. ($.89) Too bad you have no lips.",
207     "A Swiss-Army knife. All of its appendages are out. (toothpick lost)",
208     "It's a zen simulation, trapped within an ASCII character.",
209     "It's a copy of \"The Rubaiyat of Spike Schudy\".",
210     "It's \"War and Peace\" (unabridged, very small print).",
211     "A willing, ripe tomato bemoans your inability to digest fruit.",
212     "A robot comedian. You feel amused.",
213     "It's KITT, the talking car.",
214     "Here's Pete Peterson. His batteries seem to have long gone dead.",
215     "\"Blup, blup, blup\", says the mud pot.",
216     "More grist for the mill.",
217     "Grind 'em up, spit 'em out, they're twigs.",
218     "The boom box cranks out an old Ethel Merman tune.",
219     "It's \"Finding kitten\", published by O'Reilly and Associates.",
220     "Pumpkin pie spice.",
221     "It's the Bass-Matic '76! Mmm, that's good bass!",
222     "\"Lend us a fiver 'til Thursday\", pleas Andy Capp.",
223     "It's a tape of '70s rock. All original hits! All original artists!",
224     "You've found the fabled America Online disk graveyard!",
225     "Empty jewelboxes litter the landscape.",
226     "It's the astounding meta-object.",
227     "Ed McMahon stands here, lost in thought. Seeing you, he bellows, \"YES SIR!\"",
228     "...thingy???",
229     "It's 1000 secrets the government doesn't want you to know!",
230     "The letters O and R.",
231     "A magical... magic thing.",
232     "It's a moment of silence.",
233     "It's Sirhan-Sirhan, looking guilty.",
234     "It's \"Chicken Soup for the Kitten-seeking Soulless Robot.\"",
235     "It is a set of wind-up chatter teeth.",
236     "It is a cloud shaped like an ox.",
237     "You see a snowflake here, melting slowly.",
238     "It's a big block of ice. Something seems to be frozen inside it.",
239     "Vladimir Lenin's casket rests here.",
240     "It's a copy of \"Zen and The Art of Robot Maintenance\".",
241     "This invisible box contains a pantomime horse.",
242     "A mason jar lies here open. It's label reads: \"do not open!\".",
243     "A train of thought chugs through here.",
244     "This jar of pickles expired in 1957.",
245     "Someone's identity disk lies here.",
246     "\"Yes!\" says the bit.",
247     "\"No!\" says the bit.",
248     "A dodecahedron bars your way.",
249     "Mr. Hooper is here, surfing.",
250     "It's a big smoking fish.",
251     "You have new mail in /var/spool/robot",
252     "Just a monitor with the blue element burnt out.",
253     "A pile of coaxial plumbing lies here.",
254     "It's a rotten old shoe.",
255     "It's a hundred-dollar bill.",
256     "It's a Dvorak keyboard.",
257     "It's a cardboard box full of 8-tracks.",
258     "Just a broken hard drive containg the archives of Nerth Pork.",
259     "A broken metronome sits here, it's needle off to one side.",
260     "A sign reads: \"Go home!\"",
261     "A sign reads: \"No robots allowed!\"",
262     "It's the handheld robotfindskitten game, by Tiger.",
263     "This particular monstrosity appears to be ENIAC.",
264     "This is a tasty-looking banana creme pie.",
265     "A wireframe model of a hot dog rotates in space here.",
266     "Just the empty husk of a locust.",
267     "You disturb a murder of crows.",
268     "It's a copy of the robotfindskitten EULA.",
269     "It's Death.",
270     "It's an autographed copy of \"Secondary Colors,\" by Bob Ross.",
271     "It is a marzipan dreadnought that appears to have melted and stuck.",
272     "It's a DVD of \"Crouching Monkey, Hidden Kitten\", region encoded for the moon.",
273     "It's Kieran Hervold.  Damn dyslexia!",
274     "A non-descript box of crackers.",
275     "Carbonated Water, High Fructose Corn Syrup, Color, Phosphoric Acid, Flavors, Caffeine.",
276     "\"Move along! Nothing to see here!\"",
277     "It's the embalmed corpse of Vladimir Lenin.",
278     "A coupon for one free steak-fish at your local family diner.",
279     "A set of keys to a 2001 Rolls Royce. Worthless."
280   };
281
282 GtkWidget *arena[ARENA_WIDTH][ARENA_HEIGHT];
283 GtkWidget *table, *window, *robot, *kitten;
284 int robot_x, robot_y;
285 gboolean used[G_N_ELEMENTS (messages)] = { 0, };
286
287 GdkPixbuf *robot_pic, *love_pic, *kitten_pic;
288 GtkWidget *animation_area;
289
290 const GdkColor black = { 0, };
291
292 /****************************************************************/
293 /* Random object descriptions.                                  */
294 /****************************************************************/
295
296 char *
297 description (void)
298 {
299   int r;
300    
301   do
302     {
303       r = random() % G_N_ELEMENTS (messages);
304     }
305   while (used[r]);
306
307   used[r] = TRUE;
308   return messages[r];
309         
310 }
311
312 /****************************************************************/
313 /* Placing objects.                                             */
314 /****************************************************************/
315
316 void
317 place_in_arena_at_xy (GtkWidget *item, int x, int y)
318 {
319   arena[x][y] = item;
320
321   gtk_table_attach_defaults (GTK_TABLE (table),
322                              item,
323                              x, x+1,
324                              y, y+1);
325
326   if (item==robot)
327     {
328       robot_x = x;
329       robot_y = y;
330     }
331 }
332
333 void
334 place_in_arena_randomly (GtkWidget *item)
335 {
336   int x, y;
337    
338   do
339     {
340       x = random() % ARENA_WIDTH;
341       y = random() % ARENA_HEIGHT;
342     }
343   while (arena[x][y]);
344
345   place_in_arena_at_xy (item, x, y);
346 }
347
348 /****************************************************************/
349 /* Labels representing things the robot might find.             */
350 /****************************************************************/
351
352 GtkWidget *
353 random_character (gchar *description)
354 {
355   gchar character[2] = { random() % ('~'-'!') + '!', 0 };
356   gchar *escaped_character = g_markup_escape_text (character, -1);
357   gchar *markup = g_strdup_printf ("<span color=\"#%02x%02x%02x\">%s</span>",
358                                    (int) (random() % 0x7F)+0x80,
359                                    (int) (random() % 0x7F)+0x80,
360                                    (int) (random() % 0x7F)+0x80,
361                                    escaped_character);
362   GtkWidget *result = gtk_label_new (NULL);
363   gtk_label_set_markup (GTK_LABEL (result), markup);
364   g_free (markup);
365   g_free (escaped_character);
366
367   g_object_set_data (G_OBJECT (result), "examine", description);
368
369   return result;
370 }
371
372 /****************************************************************/
373 /* Talking back to the user.                                    */
374 /****************************************************************/
375
376 void
377 show_message (const char *message)
378 {
379   HildonNote* note = HILDON_NOTE
380     (hildon_note_new_information (GTK_WINDOW (window),
381                                   message));
382   gtk_dialog_run (GTK_DIALOG (note));
383   gtk_widget_destroy (GTK_WIDGET (note));
384 }
385
386 /****************************************************************/
387 /* The ending animation.                                        */
388 /****************************************************************/
389
390 static gboolean
391 ending_animation_quit (gpointer data)
392 {
393   gtk_main_quit ();
394   return FALSE;
395 }
396
397 static gboolean
398 ending_animation_draw (GtkWidget *widget, GdkEventExpose *event, gpointer data)
399 {
400   /* We only run through once, so just make it static. */
401   static int cycle_count = 0;
402
403   static int robot_x = 0;
404   static int robot_stop = 0;
405   static int kitten_x = 0;
406   static int all_y = 0;
407
408   const int stepsize = 3;
409
410   if (!kitten_x)
411     {
412       all_y = (event->area.height - gdk_pixbuf_get_height (love_pic)) / 2;
413
414       robot_stop = gdk_pixbuf_get_width (robot_pic) + gdk_pixbuf_get_width (love_pic);
415       kitten_x = event->area.width - (cycle_count*stepsize + gdk_pixbuf_get_width (kitten_pic));
416     }
417
418   gdk_gc_set_foreground (widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
419                          &black);
420
421   gdk_draw_rectangle (GDK_DRAWABLE(widget->window),
422                       widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
423                       TRUE,
424                       0, 0, event->area.width, event->area.height);
425
426   gdk_draw_pixbuf (GDK_DRAWABLE(widget->window),
427                    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
428                    robot_pic, 0, 0,
429                    robot_x, all_y,
430                    -1, -1,
431                    GDK_RGB_DITHER_NONE, 0, 0);
432
433   gdk_draw_pixbuf (GDK_DRAWABLE(widget->window),
434                    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
435                    kitten_pic, 0, 0,
436                    kitten_x, all_y,
437                    -1, -1,
438                    GDK_RGB_DITHER_NONE, 0, 0);
439
440   cycle_count++;
441   robot_x += stepsize;
442   kitten_x -= stepsize;
443
444   if (robot_x+robot_stop >= kitten_x)
445     {
446       gdk_draw_pixbuf (GDK_DRAWABLE(widget->window),
447                        widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
448                        love_pic, 0, 0,
449                        robot_x + gdk_pixbuf_get_width (robot_pic), all_y,
450                        -1, -1,
451                        GDK_RGB_DITHER_NONE, 0, 0);
452
453       g_object_unref (love_pic);
454       love_pic = NULL;
455
456       g_timeout_add (2000, ending_animation_quit, NULL);
457     }
458
459   return TRUE;
460 }
461
462 static gboolean
463 ending_animation_step (gpointer data)
464 {
465   if (love_pic)
466     {
467       gdk_window_invalidate_rect (animation_area->window,
468                                   NULL, TRUE);
469
470       return TRUE;
471     }
472   else
473     return FALSE;
474 }
475
476 static void
477 ending_animation ()
478 {
479   robot_pic = gdk_pixbuf_new_from_file ("/usr/share/rfk/rfk-robot.png", NULL);
480   love_pic = gdk_pixbuf_new_from_file ("/usr/share/rfk/rfk-love.png", NULL);
481   kitten_pic = gdk_pixbuf_new_from_file ("/usr/share/rfk/rfk-kitten.png", NULL);
482   animation_area =  gtk_drawing_area_new ();
483
484   gtk_container_remove (GTK_CONTAINER (window), GTK_WIDGET (table));
485   gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (animation_area));
486   gtk_widget_show_all (window);
487
488   g_signal_connect (G_OBJECT (animation_area),
489                     "expose_event", G_CALLBACK (ending_animation_draw), NULL);
490   g_timeout_add (10, ending_animation_step, NULL);
491 }
492
493 /****************************************************************/
494 /* Moving the robot.  Way to go, robot!                         */
495 /****************************************************************/
496
497 typedef struct {
498   guint gdk_key;
499   gchar vi_key; /* or nethack equivalent */
500   guint8 move_x;
501   guint8 move_y;
502 } direction;
503
504 direction directions[] = {
505   { GDK_Home,      'y', -1, -1 },
506   { GDK_Left,      'h', -1,  0 },
507   { GDK_End,       'b', -1,  1 },
508   { GDK_Down,      'j',  0,  1 },
509   { GDK_Page_Down, 'n',  1,  1 },
510   { GDK_Right,     'l',  1,  0 },
511   { GDK_Page_Up,   'u',  1, -1 },
512   { GDK_Up,        'k',  0, -1 }
513 };
514
515 gboolean
516 move_robot (guint8 whichway)
517 {
518   GtkWidget *new_space;
519   gint8 dx = directions[whichway].move_x;
520   gint8 dy = directions[whichway].move_y;
521
522   const char *found;
523
524   if (robot_x+dx<0 ||
525       robot_y+dy<0 ||
526       robot_x+dx>=ARENA_WIDTH ||
527       robot_y+dy>=ARENA_HEIGHT)
528     return TRUE;
529
530   new_space = arena[robot_x+dx][robot_y+dy];
531   found = g_object_get_data (G_OBJECT (new_space), "examine");
532
533   if (found && *found)
534     {
535       show_message (found);
536
537       if (new_space == kitten)
538         {
539           ending_animation ();
540         }
541
542       return TRUE;
543     }
544   else
545     {
546       /* just an ordinary move into an empty space */
547
548       g_object_ref (new_space);
549
550       gtk_container_remove (GTK_CONTAINER (table), robot);
551       gtk_container_remove (GTK_CONTAINER (table), new_space);
552
553       place_in_arena_at_xy (new_space, robot_x, robot_y);
554       place_in_arena_at_xy (robot, robot_x+dx, robot_y+dy);
555
556       g_object_unref (new_space);
557
558       return FALSE;
559     }
560 }
561
562 /****************************************************************/
563 /* Event handlers.                                              */
564 /****************************************************************/
565
566 gboolean
567 on_window_clicked (GtkWidget      *widget,
568                    GdkEventButton *event,
569                    gpointer        user_data)
570 {
571   /** Centre point of robot's representation on screen */
572   int rx, ry;
573   double angle;
574
575   rx = (robot->allocation.x+robot->allocation.width/2);
576   ry = (robot->allocation.y+robot->allocation.height/2);
577
578   angle = atan2(event->x - rx,
579                 event->y - ry) +
580     M_PI +
581     M_PI/8;
582
583   move_robot (((int) (angle / (M_PI/4)))-1);
584
585   return TRUE;
586 }
587
588 gboolean
589 on_key_pressed (GtkWidget      *widget,
590                 GdkEventKey    *event,
591                 gpointer        user_data)
592 {
593   gint i;
594   guint keyval = event->keyval;
595
596   if (keyval>='A' && keyval<='Z')
597     {
598       keyval += ('a'-'A');
599     }
600
601   for (i=0; i<G_N_ELEMENTS(directions); i++)
602     {
603       if (keyval==directions[i].gdk_key ||
604           keyval==directions[i].vi_key)
605         {
606           if (event->state & GDK_SHIFT_MASK)
607             {
608               while (!move_robot (i))
609                 {
610                   /* keep going, robot! */
611                 }
612             }
613           else
614             {
615               move_robot (i);
616             }
617           return FALSE;
618         }
619     }
620
621   return FALSE;
622 }
623
624 /****************************************************************/
625 /* Let's kick the whole thing off...                            */
626 /****************************************************************/
627
628 int
629 main (gint argc,
630       gchar **argv)
631 {
632   int x, y;
633
634   gtk_init (&argc, &argv);
635   g_set_application_name ("robotfindskitten");
636   srandom (time(0));
637
638   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
639   gtk_window_set_title (GTK_WINDOW (window), "robotfindskitten");
640   gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &black);
641   g_signal_connect (G_OBJECT (window), "button-press-event", G_CALLBACK (on_window_clicked), NULL);
642   g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (on_key_pressed), NULL);
643   g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL);
644         
645   table = gtk_table_new (ARENA_HEIGHT, ARENA_WIDTH, TRUE);
646   gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (table));
647
648   robot = gtk_label_new ("#");
649   g_object_ref (robot);
650   kitten = random_character ("You found kitten!  Way to go, robot!");
651
652   place_in_arena_randomly (robot);
653   place_in_arena_randomly (kitten);
654
655   for (x=0; x < amount_of_random_stuff; x++)
656     place_in_arena_randomly (random_character (description ()));
657
658   for (x=0; x < ARENA_WIDTH; x++)
659     for (y=0; y < ARENA_HEIGHT; y++)
660       if (!arena[x][y])
661         place_in_arena_at_xy (gtk_label_new (NULL), x, y);
662
663   gtk_widget_show_all (window);
664
665   gdk_window_set_events (GTK_WIDGET (window)->window,
666                          gdk_window_get_events(GTK_WIDGET (window)->window) | GDK_BUTTON_PRESS_MASK);
667
668         
669   show_message (explanation);
670
671   gtk_main ();
672
673   return 0;
674 }