1 /* robotfindskitten for maemo
2 * original by Leonard Richardson, 1997
3 * ported to maemo by Thomas Thurman, 2009
6 * gcc -Wall -g rfk.c -o rfk `pkg-config --cflags --libs gtk+-2.0 hildon-1`
12 #include <hildon/hildon.h>
17 #define ARENA_WIDTH 25
18 #define ARENA_HEIGHT 12
20 const int amount_of_random_stuff = 15;
22 const char *explanation =
23 "In this game, you are robot (#). "
24 "Your job is to find kitten. This task is complicated "
25 "by the existence of various things which are not kitten. "
26 "Robot must touch items to determine if they are kitten or "
27 "not. The game ends when robotfindskitten. You may move "
28 "robot about by tapping on any side of robot, or with the "
34 GtkWidget *arena[ARENA_WIDTH][ARENA_HEIGHT];
35 GtkWidget *table, *window, *robot, *kitten;
37 gboolean *used = NULL;
39 GdkPixbuf *robot_pic, *love_pic, *kitten_pic;
40 GtkWidget *animation_area;
42 const GdkColor black = { 0, };
44 /****************************************************************/
45 /* Random object descriptions. */
46 /****************************************************************/
55 r = random() % nki_count;
60 return g_slist_nth_data (nki, r);
63 /****************************************************************/
64 /* Placing objects. */
65 /****************************************************************/
68 place_in_arena_at_xy (GtkWidget *item, int x, int y)
72 gtk_table_attach_defaults (GTK_TABLE (table),
85 place_in_arena_randomly (GtkWidget *item)
91 x = random() % ARENA_WIDTH;
92 y = random() % ARENA_HEIGHT;
96 place_in_arena_at_xy (item, x, y);
99 /****************************************************************/
100 /* Labels representing things the robot might find. */
101 /****************************************************************/
104 random_character (gchar *description)
106 gchar character[2] = { random() % ('~'-'!') + '!', 0 };
107 gchar *escaped_character = g_markup_escape_text (character, -1);
108 gchar *markup = g_strdup_printf ("<span color=\"#%02x%02x%02x\">%s</span>",
109 (int) (random() % 0x7F)+0x80,
110 (int) (random() % 0x7F)+0x80,
111 (int) (random() % 0x7F)+0x80,
113 GtkWidget *result = gtk_label_new (NULL);
114 gtk_label_set_markup (GTK_LABEL (result), markup);
116 g_free (escaped_character);
118 g_object_set_data (G_OBJECT (result), "examine", description);
123 /****************************************************************/
124 /* Talking back to the user. */
125 /****************************************************************/
128 show_message (const char *message)
130 HildonNote* note = HILDON_NOTE
131 (hildon_note_new_information (GTK_WINDOW (window),
133 gtk_dialog_run (GTK_DIALOG (note));
134 gtk_widget_destroy (GTK_WIDGET (note));
137 /****************************************************************/
138 /* Loading the non-kitten objects. */
139 /****************************************************************/
141 ensure_messages_loaded (void)
143 FILE *nki_file = NULL;
145 gboolean headers = TRUE;
150 nki_file = fopen ("/usr/share/rfk/non-kitten-items.rfk", "r");
154 show_message ("Could not open list of non-kitten items! Must quit.");
158 while (!feof (nki_file))
161 if (fscanf (nki_file, "%a[^\n]%c", &line, &newline) == EOF)
166 if (strcmp(line, "")==0)
169 fscanf (nki_file, "%c", &newline);
174 /* we ignore all the headers for now */
179 nki = g_slist_prepend (nki, line);
186 used = g_malloc0 (nki_count);
189 /****************************************************************/
190 /* The ending animation. */
191 /****************************************************************/
194 ending_animation_quit (gpointer data)
201 ending_animation_draw (GtkWidget *widget, GdkEventExpose *event, gpointer data)
203 /* We only run through once, so just make it static. */
204 static int cycle_count = 0;
206 static int robot_x = 0;
207 static int robot_stop = 0;
208 static int kitten_x = 0;
209 static int all_y = 0;
211 const int stepsize = 3;
215 all_y = (event->area.height - gdk_pixbuf_get_height (love_pic)) / 2;
217 robot_stop = gdk_pixbuf_get_width (robot_pic) + gdk_pixbuf_get_width (love_pic);
218 kitten_x = event->area.width - (cycle_count*stepsize + gdk_pixbuf_get_width (kitten_pic));
221 gdk_gc_set_foreground (widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
224 gdk_draw_rectangle (GDK_DRAWABLE(widget->window),
225 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
227 0, 0, event->area.width, event->area.height);
229 gdk_draw_pixbuf (GDK_DRAWABLE(widget->window),
230 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
234 GDK_RGB_DITHER_NONE, 0, 0);
236 gdk_draw_pixbuf (GDK_DRAWABLE(widget->window),
237 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
241 GDK_RGB_DITHER_NONE, 0, 0);
245 kitten_x -= stepsize;
247 if (robot_x+robot_stop >= kitten_x)
249 gdk_draw_pixbuf (GDK_DRAWABLE(widget->window),
250 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
252 robot_x + gdk_pixbuf_get_width (robot_pic), all_y,
254 GDK_RGB_DITHER_NONE, 0, 0);
256 g_object_unref (love_pic);
259 g_timeout_add (2000, ending_animation_quit, NULL);
266 ending_animation_step (gpointer data)
270 gdk_window_invalidate_rect (animation_area->window,
282 robot_pic = gdk_pixbuf_new_from_file ("/usr/share/rfk/rfk-robot.png", NULL);
283 love_pic = gdk_pixbuf_new_from_file ("/usr/share/rfk/rfk-love.png", NULL);
284 kitten_pic = gdk_pixbuf_new_from_file ("/usr/share/rfk/rfk-kitten.png", NULL);
285 animation_area = gtk_drawing_area_new ();
287 gtk_container_remove (GTK_CONTAINER (window), GTK_WIDGET (table));
288 gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (animation_area));
289 gtk_widget_show_all (window);
291 g_signal_connect (G_OBJECT (animation_area),
292 "expose_event", G_CALLBACK (ending_animation_draw), NULL);
293 g_timeout_add (10, ending_animation_step, NULL);
296 /****************************************************************/
297 /* Moving the robot. Way to go, robot! */
298 /****************************************************************/
302 gchar vi_key; /* or nethack equivalent */
307 direction directions[] = {
308 { GDK_Home, 'y', -1, -1 },
309 { GDK_Left, 'h', -1, 0 },
310 { GDK_End, 'b', -1, 1 },
311 { GDK_Down, 'j', 0, 1 },
312 { GDK_Page_Down, 'n', 1, 1 },
313 { GDK_Right, 'l', 1, 0 },
314 { GDK_Page_Up, 'u', 1, -1 },
315 { GDK_Up, 'k', 0, -1 }
319 move_robot (guint8 whichway)
321 GtkWidget *new_space;
322 gint8 dx = directions[whichway].move_x;
323 gint8 dy = directions[whichway].move_y;
329 robot_x+dx>=ARENA_WIDTH ||
330 robot_y+dy>=ARENA_HEIGHT)
333 new_space = arena[robot_x+dx][robot_y+dy];
334 found = g_object_get_data (G_OBJECT (new_space), "examine");
338 show_message (found);
340 if (new_space == kitten)
349 /* just an ordinary move into an empty space */
351 g_object_ref (new_space);
353 gtk_container_remove (GTK_CONTAINER (table), robot);
354 gtk_container_remove (GTK_CONTAINER (table), new_space);
356 place_in_arena_at_xy (new_space, robot_x, robot_y);
357 place_in_arena_at_xy (robot, robot_x+dx, robot_y+dy);
359 g_object_unref (new_space);
365 /****************************************************************/
366 /* Event handlers. */
367 /****************************************************************/
370 on_window_clicked (GtkWidget *widget,
371 GdkEventButton *event,
374 /** Centre point of robot's representation on screen */
378 rx = (robot->allocation.x+robot->allocation.width/2);
379 ry = (robot->allocation.y+robot->allocation.height/2);
381 angle = atan2(event->x - rx,
385 move_robot (((int) (angle / (M_PI/4))) % 8);
391 on_key_pressed (GtkWidget *widget,
396 guint keyval = event->keyval;
398 if (keyval>='A' && keyval<='Z')
403 for (i=0; i<G_N_ELEMENTS(directions); i++)
405 if (keyval==directions[i].gdk_key ||
406 keyval==directions[i].vi_key)
408 if (event->state & GDK_SHIFT_MASK)
410 while (!move_robot (i))
412 /* keep going, robot! */
426 /****************************************************************/
427 /* Let's kick the whole thing off... */
428 /****************************************************************/
436 gtk_init (&argc, &argv);
437 g_set_application_name ("robotfindskitten");
440 ensure_messages_loaded ();
442 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
443 gtk_window_set_title (GTK_WINDOW (window), "robotfindskitten");
444 gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &black);
445 g_signal_connect (G_OBJECT (window), "button-press-event", G_CALLBACK (on_window_clicked), NULL);
446 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (on_key_pressed), NULL);
447 g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL);
449 table = gtk_table_new (ARENA_HEIGHT, ARENA_WIDTH, TRUE);
450 gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (table));
452 robot = gtk_label_new ("#");
453 g_object_ref (robot);
454 kitten = random_character ("You found kitten! Way to go, robot!");
456 place_in_arena_randomly (robot);
457 place_in_arena_randomly (kitten);
459 for (x=0; x < amount_of_random_stuff; x++)
460 place_in_arena_randomly (random_character (description ()));
462 for (x=0; x < ARENA_WIDTH; x++)
463 for (y=0; y < ARENA_HEIGHT; y++)
465 place_in_arena_at_xy (gtk_label_new (NULL), x, y);
467 gtk_widget_show_all (window);
469 gdk_window_set_events (GTK_WIDGET (window)->window,
470 gdk_window_get_events(GTK_WIDGET (window)->window) | GDK_BUTTON_PRESS_MASK);
473 show_message (explanation);