1 #include "config.h"
2 
3 #include <string.h>
4 #include <math.h>
5 
6 #include <gegl.h>
7 #include <gtk/gtk.h>
8 #include <gdk/gdkkeysyms.h>
9 
10 #include "libgimpwidgets/gimpwidgets.h"
11 
12 #include "lebl-dialog.h"
13 
14 #include "gimp-intl.h"
15 
16 /* phish code */
17 #define PHSHFRAMES 8
18 #define PHSHORIGWIDTH 288
19 #define PHSHORIGHEIGHT 22
20 #define PHSHWIDTH (PHSHORIGWIDTH/PHSHFRAMES)
21 #define PHSHHEIGHT PHSHORIGHEIGHT
22 #define PHSHCHECKTIMEOUT (g_random_int()%120*1000)
23 #define PHSHTIMEOUT 120
24 #define PHSHHIDETIMEOUT 80
25 #define PHSHXS 5
26 #define PHSHYS ((g_random_int() % 2) + 1)
27 #define PHSHXSHIDEFACTOR 2.5
28 #define PHSHYSHIDEFACTOR 2.5
29 #define PHSHPIXELSTOREMOVE(p) (p[3] < 55 || p[2] > 200)
30 
31 static void
phsh_unsea(GdkPixbuf * gp)32 phsh_unsea(GdkPixbuf *gp)
33 {
34         guchar *pixels = gdk_pixbuf_get_pixels (gp);
35         int rs = gdk_pixbuf_get_rowstride (gp);
36 	int w = gdk_pixbuf_get_width (gp);
37         int h = gdk_pixbuf_get_height (gp);
38         int x, y;
39 
40         for (y = 0; y < h; y++, pixels += rs) {
41                 guchar *p = pixels;
42                 for (x = 0; x < w; x++, p+=4) {
43                         if (PHSHPIXELSTOREMOVE(p))
44                                p[3] = 0;
45                 }
46         }
47 }
48 
49 static GdkPixbuf *
get_phsh_frame(GdkPixbuf * pb,int frame)50 get_phsh_frame (GdkPixbuf *pb, int frame)
51 {
52         GdkPixbuf *newpb;
53 
54         newpb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
55 				PHSHWIDTH, PHSHHEIGHT);
56         gdk_pixbuf_copy_area (pb, frame * PHSHWIDTH, 0,
57 			      PHSHWIDTH, PHSHHEIGHT, newpb, 0, 0);
58 
59 	return newpb;
60 }
61 
62 typedef struct {
63 	gboolean live;
64 	int x, y;
65 } InvGoat;
66 
67 typedef struct {
68 	gboolean good;
69 	int y;
70 	int x;
71 } InvShot;
72 
73 
74 static GtkWidget *geginv = NULL;
75 static GtkWidget *geginv_canvas = NULL;
76 static GtkWidget *geginv_label = NULL;
77 static GdkPixbuf *inv_goat1 = NULL;
78 static GdkPixbuf *inv_goat2 = NULL;
79 static GdkPixbuf *inv_phsh1 = NULL;
80 static GdkPixbuf *inv_phsh2 = NULL;
81 static int inv_phsh_state = 0;
82 static int inv_goat_state = 0;
83 static int inv_width = 0;
84 static int inv_height = 0;
85 static int inv_goat_width = 0;
86 static int inv_goat_height = 0;
87 static int inv_phsh_width = 0;
88 static int inv_phsh_height = 0;
89 #define INV_ROWS 3
90 #define INV_COLS 5
91 static InvGoat invs[INV_COLS][INV_ROWS] = { { { FALSE, 0, 0 } } };
92 static int inv_num = INV_ROWS * INV_COLS;
93 static double inv_factor = 1.0;
94 static int inv_our_x = 0;
95 static int inv_x = 0;
96 static int inv_y = 0;
97 static int inv_first_col = 0;
98 static int inv_last_col = INV_COLS-1;
99 static int inv_level = 0;
100 static int inv_lives = 0;
101 static gboolean inv_do_pause = FALSE;
102 static gboolean inv_reverse = FALSE;
103 static gboolean inv_game_over = FALSE;
104 static gboolean inv_left_pressed = FALSE;
105 static gboolean inv_right_pressed = FALSE;
106 static gboolean inv_fire_pressed = FALSE;
107 static gboolean inv_left_released = FALSE;
108 static gboolean inv_right_released = FALSE;
109 static gboolean inv_fire_released = FALSE;
110 static gboolean inv_paused = FALSE;
111 static GSList *inv_shots = NULL;
112 static guint inv_draw_idle = 0;
113 
114 static void
inv_show_status(void)115 inv_show_status (void)
116 {
117 	gchar *s, *t, *u, *v, *w;
118 	if (geginv == NULL)
119 		return;
120 
121 	if (inv_game_over) {
122 		t = g_strdup_printf (_("<b>GAME OVER</b> at level %d!"),
123 				     inv_level+1);
124 		u = g_strdup_printf ("<big>%s</big>", t);
125 		/* Translators: the first and third strings are similar to a
126 		 * title, and the second string is a small information text.
127 		 * The spaces are there only to separate all the strings, so
128 		 try to keep them as is. */
129 		s = g_strdup_printf (_("%1$s   %2$s   %3$s"),
130 				     u, _("Press 'q' to quit"), u);
131 		g_free (t);
132 		g_free (u);
133 
134 	} else if (inv_paused) {
135 		t = g_strdup_printf("<big><b>%s</b></big>", _("Paused"));
136 		/* Translators: the first string is a title and the second
137 		 * string is a small information text. */
138 		s = g_strdup_printf (_("%1$s\t%2$s"),
139 				     t, _("Press 'p' to unpause"));
140 		g_free (t);
141 
142 	} else {
143 		t = g_strdup_printf ("<b>%d</b>", inv_level+1);
144 		u = g_strdup_printf ("<b>%d</b>", inv_lives);
145 		v = g_strdup_printf (_("Level: %s,  Lives: %s"), t, u);
146 		w = g_strdup_printf ("<big>%s</big>", v);
147 		/* Translators: the first string is a title and the second
148 		 * string is a small information text. */
149 		s = g_strdup_printf (_("%1$s\t%2$s"), w,
150 				     _("Left/Right to move, Space to fire, 'p' to pause, 'q' to quit"));
151 		g_free (t);
152 		g_free (u);
153 		g_free (v);
154 		g_free (w);
155 
156 	}
157 	gtk_label_set_markup (GTK_LABEL (geginv_label), s);
158 
159 	g_free (s);
160 }
161 
162 static gboolean
inv_draw(gpointer data)163 inv_draw (gpointer data)
164 {
165         inv_draw_idle = 0;
166 
167         if (geginv)
168                 gtk_widget_queue_draw (data);
169 
170         return FALSE;
171 }
172 
173 static void
inv_queue_draw(GtkWidget * window)174 inv_queue_draw (GtkWidget *window)
175 {
176        if (inv_draw_idle == 0)
177                inv_draw_idle = g_idle_add (inv_draw, window);
178 }
179 
180 static void
inv_draw_explosion(int x,int y)181 inv_draw_explosion (int x, int y)
182 {
183         cairo_t *cr;
184         int i;
185 
186         if ( ! gtk_widget_is_drawable (geginv_canvas))
187                 return;
188 
189         cr = gdk_cairo_create ( gtk_widget_get_window (geginv_canvas));
190 
191         cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
192 
193         for (i = 5; i < 100; i += 5) {
194                 cairo_arc (cr, x, y, i, 0, 2 * G_PI);
195                 cairo_fill (cr);
196                 gdk_flush ();
197                 g_usleep (50000);
198         }
199 
200         cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
201 
202         for (i = 5; i < 100; i += 5) {
203                 cairo_arc (cr, x, y, i, 0, 2 * G_PI);
204                 cairo_fill (cr);
205                 gdk_flush ();
206                 g_usleep (50000);
207         }
208 
209         cairo_destroy (cr);
210 
211 	inv_queue_draw (geginv);
212 }
213 
214 
215 static void
inv_do_game_over(void)216 inv_do_game_over (void)
217 {
218 	GSList *li;
219 
220 	inv_game_over = TRUE;
221 
222 	for (li = inv_shots; li != NULL; li = li->next) {
223 		InvShot *shot = li->data;
224 		shot->good = FALSE;
225 	}
226 
227 	inv_queue_draw (geginv);
228 
229 	inv_show_status ();
230 }
231 
232 
233 static GdkPixbuf *
pb_scale(GdkPixbuf * pb,double scale)234 pb_scale (GdkPixbuf *pb, double scale)
235 {
236 	int w, h;
237 
238 	if (scale == 1.0)
239 		return (GdkPixbuf *)g_object_ref ((GObject *)pb);
240 
241 	w = gdk_pixbuf_get_width (pb) * scale;
242 	h = gdk_pixbuf_get_height (pb) * scale;
243 
244 	return gdk_pixbuf_scale_simple (pb, w, h,
245 					GDK_INTERP_BILINEAR);
246 }
247 
248 static void
refind_first_and_last(void)249 refind_first_and_last (void)
250 {
251 	int i, j;
252 
253 	for (i = 0; i < INV_COLS; i++) {
254 		gboolean all_null = TRUE;
255 		for (j = 0; j < INV_ROWS; j++) {
256 			if (invs[i][j].live) {
257 				all_null = FALSE;
258 				break;
259 			}
260 		}
261 		if ( ! all_null) {
262 			inv_first_col = i;
263 			break;
264 		}
265 	}
266 
267 	for (i = INV_COLS-1; i >= 0; i--) {
268 		gboolean all_null = TRUE;
269 		for (j = 0; j < INV_ROWS; j++) {
270 			if (invs[i][j].live) {
271 				all_null = FALSE;
272 				break;
273 			}
274 		}
275 		if ( ! all_null) {
276 			inv_last_col = i;
277 			break;
278 		}
279 	}
280 }
281 
282 static void
whack_gegl(int i,int j)283 whack_gegl (int i, int j)
284 {
285 	if ( ! invs[i][j].live)
286 		return;
287 
288 	invs[i][j].live = FALSE;
289 	inv_num --;
290 
291 	if (inv_num > 0) {
292 		refind_first_and_last ();
293 	} else {
294 		inv_x = 70;
295 		inv_y = 70;
296 		inv_first_col = 0;
297 		inv_last_col = INV_COLS-1;
298 		inv_reverse = FALSE;
299 
300 		g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
301 		g_slist_free (inv_shots);
302 		inv_shots = NULL;
303 
304 		for (i = 0; i < INV_COLS; i++) {
305 			for (j = 0; j < INV_ROWS; j++) {
306 				invs[i][j].live = TRUE;
307 				invs[i][j].x = 70 + i * 100;
308 				invs[i][j].y = 70 + j * 80;
309 			}
310 		}
311 		inv_num = INV_ROWS * INV_COLS;
312 
313 		inv_level ++;
314 
315 		inv_show_status ();
316 	}
317 
318 	inv_queue_draw (geginv);
319 }
320 
321 static gboolean
geginv_timeout(gpointer data)322 geginv_timeout (gpointer data)
323 {
324 	int i, j;
325 	int limitx1;
326 	int limitx2;
327 	int speed;
328 	int shots;
329 	int max_shots;
330 
331 	if (inv_paused)
332 		return TRUE;
333 
334 	if (geginv != data ||
335 	    inv_num <= 0 ||
336 	    inv_y > 700)
337 		return FALSE;
338 
339 	limitx1 = 70 - (inv_first_col * 100);
340 	limitx2 = 800 - 70 - (inv_last_col * 100);
341 
342 	if (inv_game_over) {
343 		inv_y += 30;
344 	} else {
345 		if (inv_num < (INV_COLS*INV_ROWS)/3)
346 			speed = 45+2*inv_level;
347 		else if (inv_num < (2*INV_COLS*INV_ROWS)/3)
348 			speed = 30+2*inv_level;
349 		else
350 			speed = 15+2*inv_level;
351 
352 		if (inv_reverse) {
353 			inv_x -= speed;
354 			if (inv_x < limitx1) {
355 				inv_reverse = FALSE;
356 				inv_x = (limitx1 + (limitx1 - inv_x));
357 				inv_y += 30+inv_level;
358 			}
359 		} else {
360 			inv_x += speed;
361 			if (inv_x > limitx2) {
362 				inv_reverse = TRUE;
363 				inv_x = (limitx2 - (inv_x - limitx2));
364 				inv_y += 30+inv_level;
365 			}
366 		}
367 	}
368 
369 	for (i = 0; i < INV_COLS; i++) {
370 		for (j = 0; j < INV_ROWS; j++) {
371 			if (invs[i][j].live) {
372 				invs[i][j].x = inv_x + i * 100;
373 				invs[i][j].y = inv_y + j * 80;
374 
375 				if ( ! inv_game_over &&
376 				    invs[i][j].y >= 570) {
377 					inv_do_game_over ();
378 				} else if ( ! inv_game_over &&
379 					   invs[i][j].y >= 530 &&
380 					   invs[i][j].x + 40 > inv_our_x - 25 &&
381 					   invs[i][j].x - 40 < inv_our_x + 25) {
382 					whack_gegl (i,j);
383 					inv_lives --;
384 					inv_draw_explosion (inv_our_x, 550);
385 					if (inv_lives <= 0) {
386 						inv_do_game_over ();
387 					} else {
388 						g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
389 						g_slist_free (inv_shots);
390 						inv_shots = NULL;
391 						inv_our_x = 400;
392 						inv_do_pause = TRUE;
393 						inv_show_status ();
394 					}
395 				}
396 			}
397 		}
398 	}
399 
400 	shots = 0;
401 	max_shots = (g_random_int () >> 3) % (2+inv_level);
402 	while ( ! inv_game_over && shots < MIN (max_shots, inv_num)) {
403 		int i = (g_random_int () >> 3) % INV_COLS;
404 		for (j = INV_ROWS-1; j >= 0; j--) {
405 			if (invs[i][j].live) {
406 				InvShot *shot = g_new0 (InvShot, 1);
407 
408 				shot->good = FALSE;
409 				shot->x = invs[i][j].x + (g_random_int () % 6) - 3;
410 				shot->y = invs[i][j].y + inv_goat_height/2 + (g_random_int () % 3);
411 
412 				inv_shots = g_slist_prepend (inv_shots, shot);
413 				shots++;
414 				break;
415 			}
416 		}
417 	}
418 
419 	inv_goat_state = (inv_goat_state+1) % 2;
420 
421 	inv_queue_draw (geginv);
422 
423 	g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv);
424 
425 	return FALSE;
426 }
427 
428 static gboolean
find_gegls(int x,int y)429 find_gegls (int x, int y)
430 {
431 	int i, j;
432 
433 	/* FIXME: this is stupid, we can do better */
434 	for (i = 0; i < INV_COLS; i++) {
435 		for (j = 0; j < INV_ROWS; j++) {
436 			int ix = invs[i][j].x;
437 			int iy = invs[i][j].y;
438 
439 			if ( ! invs[i][j].live)
440 				continue;
441 
442 			if (y >= iy - 30 &&
443 			    y <= iy + 30 &&
444 			    x >= ix - 40 &&
445 			    x <= ix + 40) {
446 				whack_gegl (i, j);
447 				return TRUE;
448 			}
449 		}
450 	}
451 
452 	return FALSE;
453 }
454 
455 
456 static gboolean
geginv_move_timeout(gpointer data)457 geginv_move_timeout (gpointer data)
458 {
459 	GSList *li;
460 	static int shot_inhibit = 0;
461 
462 	if (inv_paused)
463 		return TRUE;
464 
465 	if (geginv != data ||
466 	    inv_num <= 0 ||
467 	    inv_y > 700)
468 		return FALSE;
469 
470 	inv_phsh_state = (inv_phsh_state+1)%10;
471 
472 	/* we will be drawing something */
473 	if (inv_shots != NULL)
474 		inv_queue_draw (geginv);
475 
476 	li = inv_shots;
477 	while (li != NULL) {
478 		InvShot *shot = li->data;
479 
480 		if (shot->good) {
481 			shot->y -= 30;
482 			if (find_gegls (shot->x, shot->y) ||
483 			    shot->y <= 0) {
484 				GSList *list = li;
485 				/* we were restarted */
486 				if (inv_shots == NULL)
487 					return TRUE;
488 				li = li->next;
489 				g_free (shot);
490 				inv_shots = g_slist_delete_link (inv_shots, list);
491 				continue;
492 			}
493 		} else /* bad */ {
494 			shot->y += 30;
495 			if ( ! inv_game_over &&
496 			    shot->y >= 535 &&
497 			    shot->y <= 565 &&
498 			    shot->x >= inv_our_x - 25 &&
499 			    shot->x <= inv_our_x + 25) {
500 				inv_lives --;
501 				inv_draw_explosion (inv_our_x, 550);
502 				if (inv_lives <= 0) {
503 					inv_do_game_over ();
504 				} else {
505 					g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
506 					g_slist_free (inv_shots);
507 					inv_shots = NULL;
508 					inv_our_x = 400;
509 					inv_do_pause = TRUE;
510 					inv_show_status ();
511 					return TRUE;
512 				}
513 			}
514 
515 			if (shot->y >= 600) {
516 				GSList *list = li;
517 				li = li->next;
518 				g_free (shot);
519 				inv_shots = g_slist_delete_link (inv_shots, list);
520 				continue;
521 			}
522 		}
523 
524 		li = li->next;
525 	}
526 
527 	if ( ! inv_game_over) {
528 		if (inv_left_pressed && inv_our_x > 100) {
529 			inv_our_x -= 20;
530 			inv_queue_draw (geginv);
531 		} else if (inv_right_pressed && inv_our_x < 700) {
532 			inv_our_x += 20;
533 			inv_queue_draw (geginv);
534 		}
535 	}
536 
537 	if (shot_inhibit > 0)
538 		shot_inhibit--;
539 
540 	if ( ! inv_game_over && inv_fire_pressed && shot_inhibit == 0) {
541 		InvShot *shot = g_new0 (InvShot, 1);
542 
543 		shot->good = TRUE;
544 		shot->x = inv_our_x;
545 		shot->y = 540;
546 
547 		inv_shots = g_slist_prepend (inv_shots, shot);
548 
549 		shot_inhibit = 5;
550 
551 		inv_queue_draw (geginv);
552 	}
553 
554 	if (inv_left_released)
555 		inv_left_pressed = FALSE;
556 	if (inv_right_released)
557 		inv_right_pressed = FALSE;
558 	if (inv_fire_released)
559 		inv_fire_pressed = FALSE;
560 
561 	return TRUE;
562 }
563 
564 static gboolean
inv_key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)565 inv_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
566 {
567 	switch (event->keyval) {
568 	case GDK_KEY_Left:
569 	case GDK_KEY_KP_Left:
570 	case GDK_KEY_Pointer_Left:
571 		inv_left_pressed = TRUE;
572 		inv_left_released = FALSE;
573 		return TRUE;
574 	case GDK_KEY_Right:
575 	case GDK_KEY_KP_Right:
576 	case GDK_KEY_Pointer_Right:
577 		inv_right_pressed = TRUE;
578 		inv_right_released = FALSE;
579 		return TRUE;
580 	case GDK_KEY_space:
581 	case GDK_KEY_KP_Space:
582 		inv_fire_pressed = TRUE;
583 		inv_fire_released = FALSE;
584 		return TRUE;
585 	default:
586 		break;
587 	}
588 	return FALSE;
589 }
590 
591 static gboolean
inv_key_release(GtkWidget * widget,GdkEventKey * event,gpointer data)592 inv_key_release (GtkWidget *widget, GdkEventKey *event, gpointer data)
593 {
594 	switch (event->keyval) {
595 	case GDK_KEY_Left:
596 	case GDK_KEY_KP_Left:
597 	case GDK_KEY_Pointer_Left:
598 		inv_left_released = TRUE;
599 		return TRUE;
600 	case GDK_KEY_Right:
601 	case GDK_KEY_KP_Right:
602 	case GDK_KEY_Pointer_Right:
603 		inv_right_released = TRUE;
604 		return TRUE;
605 	case GDK_KEY_space:
606 	case GDK_KEY_KP_Space:
607 		inv_fire_released = TRUE;
608 		return TRUE;
609 	case GDK_KEY_q:
610 	case GDK_KEY_Q:
611 		gtk_widget_destroy (widget);
612 		return TRUE;
613 	case GDK_KEY_p:
614 	case GDK_KEY_P:
615 		inv_paused = ! inv_paused;
616 		inv_show_status ();
617 		return TRUE;
618 	default:
619 		break;
620 	}
621 	return FALSE;
622 }
623 
624 static gboolean
ensure_creatures(void)625 ensure_creatures (void)
626 {
627         GdkPixbuf *pb, *pb1;
628 
629 	if (inv_goat1 != NULL)
630 		return TRUE;
631 
632 	pb = gdk_pixbuf_new_from_resource ("/org/gimp/lebl-dialog/wanda.png",
633                                            NULL);
634 	if (pb == NULL)
635 		return FALSE;
636 
637 	pb1 = get_phsh_frame (pb, 1);
638 	inv_phsh1 = pb_scale (pb1, inv_factor);
639 	g_object_unref (G_OBJECT (pb1));
640 	phsh_unsea (inv_phsh1);
641 
642 	pb1 = get_phsh_frame (pb, 2);
643 	inv_phsh2 = pb_scale (pb1, inv_factor);
644 	g_object_unref (G_OBJECT (pb1));
645 	phsh_unsea (inv_phsh2);
646 
647 	g_object_unref (G_OBJECT (pb));
648 
649 	pb = gdk_pixbuf_new_from_resource ("/org/gimp/lebl-dialog/gegl-1.png",
650                                            NULL);
651 	if (pb == NULL) {
652 		g_object_unref (G_OBJECT (inv_phsh1));
653 		g_object_unref (G_OBJECT (inv_phsh2));
654 		return FALSE;
655 	}
656 
657 	inv_goat1 = pb_scale (pb, inv_factor * 0.66);
658 	g_object_unref (pb);
659 
660 	pb = gdk_pixbuf_new_from_resource ("/org/gimp/lebl-dialog/gegl-2.png",
661                                            NULL);
662 	if (pb == NULL) {
663 		g_object_unref (G_OBJECT (inv_goat1));
664 		g_object_unref (G_OBJECT (inv_phsh1));
665 		g_object_unref (G_OBJECT (inv_phsh2));
666 		return FALSE;
667 	}
668 
669 	inv_goat2 = pb_scale (pb, inv_factor * 0.66);
670 	g_object_unref (pb);
671 
672 	inv_goat_width = gdk_pixbuf_get_width (inv_goat1);
673 	inv_goat_height = gdk_pixbuf_get_height (inv_goat1);
674 	inv_phsh_width = gdk_pixbuf_get_width (inv_phsh1);
675 	inv_phsh_height = gdk_pixbuf_get_height (inv_phsh1);
676 
677 	return TRUE;
678 }
679 
680 static void
geginv_destroyed(GtkWidget * w,gpointer data)681 geginv_destroyed (GtkWidget *w, gpointer data)
682 {
683 	geginv = NULL;
684 }
685 
686 static gboolean
inv_expose(GtkWidget * widget,GdkEventExpose * event)687 inv_expose (GtkWidget *widget, GdkEventExpose *event)
688 {
689         cairo_t *cr;
690 	GdkPixbuf *goat;
691 	GSList *li;
692 	int i, j;
693 
694 	if (geginv == NULL) {
695 		inv_draw_idle = 0;
696 		return TRUE;
697 	}
698 
699 	if ( ! gtk_widget_is_drawable (geginv_canvas))
700 		return TRUE;
701 
702         cr = gdk_cairo_create (gtk_widget_get_window (geginv_canvas));
703 
704         cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
705         cairo_paint (cr);
706 
707 	if (inv_goat_state == 0)
708 		goat = inv_goat1;
709 	else
710 		goat = inv_goat2;
711 
712 	for (i = 0; i < INV_COLS; i++) {
713 		for (j = 0; j < INV_ROWS; j++) {
714 			int x, y;
715 			if ( ! invs[i][j].live)
716 				continue;
717 
718 			x = invs[i][j].x*inv_factor - inv_goat_width/2,
719 			y = invs[i][j].y*inv_factor - inv_goat_height/2,
720 
721                         gdk_cairo_set_source_pixbuf (cr, goat, x, y);
722                         cairo_rectangle (cr,
723                                          x, y,
724                                          inv_goat_width,
725                                          inv_goat_height);
726                         cairo_fill (cr);
727 		}
728 	}
729 
730 	for (li = inv_shots; li != NULL; li = li->next) {
731 		InvShot *shot = li->data;
732 
733                 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
734                 cairo_rectangle (cr,
735                                  (shot->x-1)*inv_factor,
736                                  (shot->y-4)*inv_factor,
737                                  3, 8);
738                 cairo_fill (cr);
739 	}
740 
741 	if ( ! inv_game_over) {
742 		GdkPixbuf *phsh;
743 
744 		if (inv_phsh_state < 5) {
745 			phsh = inv_phsh1;
746 		} else {
747 			phsh = inv_phsh2;
748 		}
749 
750                 gdk_cairo_set_source_pixbuf (cr, phsh,
751                                              inv_our_x*inv_factor - inv_phsh_width/2,
752                                              550*inv_factor - inv_phsh_height/2);
753                 cairo_rectangle (cr,
754                                  inv_our_x*inv_factor - inv_phsh_width/2,
755                                  550*inv_factor - inv_phsh_height/2,
756                                  inv_phsh_width,
757                                  inv_phsh_height);
758                 cairo_fill (cr);
759 	}
760 
761         cairo_destroy (cr);
762 
763 	gdk_flush ();
764 
765 	if (inv_do_pause) {
766 		g_usleep (G_USEC_PER_SEC);
767 		inv_do_pause = FALSE;
768 	}
769 
770 	inv_draw_idle = 0;
771 	return TRUE;
772 }
773 
774 gboolean gimp_lebl_dialog (void);
775 
776 gboolean
gimp_lebl_dialog(void)777 gimp_lebl_dialog (void)
778 {
779 	GtkWidget *vbox;
780 	int i, j;
781 
782 	if (geginv != NULL) {
783 		gtk_window_present (GTK_WINDOW (geginv));
784 		return FALSE;
785 	}
786 
787 	inv_width = 800;
788 	inv_height = 600;
789 
790 	if (inv_width > gdk_screen_get_width (gdk_screen_get_default ()) * 0.9) {
791 		inv_width = gdk_screen_get_width (gdk_screen_get_default ()) * 0.9;
792 		inv_height = inv_width * (600.0/800.0);
793 	}
794 
795 	if (inv_height > gdk_screen_get_height (gdk_screen_get_default ()) * 0.9) {
796 		inv_height = gdk_screen_get_height (gdk_screen_get_default ()) * 0.9;
797 		inv_width = inv_height * (800.0/600.0);
798 	}
799 
800 	inv_factor = (double)inv_width / 800.0;
801 
802 	if ( ! ensure_creatures ())
803 		return FALSE;
804 
805 	geginv = gtk_window_new (GTK_WINDOW_TOPLEVEL);
806         gtk_window_set_position (GTK_WINDOW (geginv), GTK_WIN_POS_CENTER);
807 	gtk_window_set_title (GTK_WINDOW (geginv), _("Killer GEGLs from Outer Space"));
808 	g_object_set (G_OBJECT (geginv), "resizable", FALSE, NULL);
809 	g_signal_connect (G_OBJECT (geginv), "destroy",
810 			  G_CALLBACK (geginv_destroyed),
811 			  NULL);
812 
813 	geginv_canvas = gtk_drawing_area_new ();
814 	gtk_widget_set_size_request (geginv_canvas, inv_width, inv_height);
815 
816 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
817 	gtk_container_add (GTK_CONTAINER (geginv), vbox);
818 	gtk_box_pack_start (GTK_BOX (vbox), geginv_canvas, TRUE, TRUE, 0);
819 
820 	geginv_label = gtk_label_new ("");
821 	gtk_box_pack_start (GTK_BOX (vbox), geginv_label, FALSE, FALSE, 0);
822 
823 	inv_our_x = 400;
824 	inv_x = 70;
825 	inv_y = 70;
826 	inv_first_col = 0;
827 	inv_level = 0;
828 	inv_lives = 3;
829 	inv_last_col = INV_COLS-1;
830 	inv_reverse = FALSE;
831 	inv_game_over = FALSE;
832 	inv_left_pressed = FALSE;
833 	inv_right_pressed = FALSE;
834 	inv_fire_pressed = FALSE;
835 	inv_left_released = FALSE;
836 	inv_right_released = FALSE;
837 	inv_fire_released = FALSE;
838 	inv_paused = FALSE;
839 
840 	gtk_widget_add_events (geginv, GDK_KEY_RELEASE_MASK);
841 
842 	g_signal_connect (G_OBJECT (geginv), "key_press_event",
843 			  G_CALLBACK (inv_key_press), NULL);
844 	g_signal_connect (G_OBJECT (geginv), "key_release_event",
845 			  G_CALLBACK (inv_key_release), NULL);
846 	g_signal_connect (G_OBJECT (geginv_canvas), "expose_event",
847 			  G_CALLBACK (inv_expose), NULL);
848 
849 	g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
850 	g_slist_free (inv_shots);
851 	inv_shots = NULL;
852 
853 	for (i = 0; i < INV_COLS; i++) {
854 		for (j = 0; j < INV_ROWS; j++) {
855 			invs[i][j].live = TRUE;
856 			invs[i][j].x = 70 + i * 100;
857 			invs[i][j].y = 70 + j * 80;
858 		}
859 	}
860 	inv_num = INV_ROWS * INV_COLS;
861 
862 	g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv);
863 	g_timeout_add (90, geginv_move_timeout, geginv);
864 
865 	inv_show_status ();
866 
867 	gtk_widget_show_all (geginv);
868   return FALSE;
869 }
870