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