879 lines
20 KiB
C
879 lines
20 KiB
C
#include "config.h"
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include <gegl.h>
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
#include "libpikawidgets/pikawidgets.h"
|
|
|
|
#include "lebl-dialog.h"
|
|
|
|
#include "pika-intl.h"
|
|
|
|
/* phish code */
|
|
#define PHSHFRAMES 8
|
|
#define PHSHORIGWIDTH 288
|
|
#define PHSHORIGHEIGHT 22
|
|
#define PHSHWIDTH (PHSHORIGWIDTH/PHSHFRAMES)
|
|
#define PHSHHEIGHT PHSHORIGHEIGHT
|
|
#define PHSHCHECKTIMEOUT (g_random_int()%120*1000)
|
|
#define PHSHTIMEOUT 120
|
|
#define PHSHHIDETIMEOUT 80
|
|
#define PHSHXS 5
|
|
#define PHSHYS ((g_random_int() % 2) + 1)
|
|
#define PHSHXSHIDEFACTOR 2.5
|
|
#define PHSHYSHIDEFACTOR 2.5
|
|
#define PHSHPIXELSTOREMOVE(p) (p[3] < 55 || p[2] > 200)
|
|
|
|
static void
|
|
phsh_unsea(GdkPixbuf *gp)
|
|
{
|
|
guchar *pixels = gdk_pixbuf_get_pixels (gp);
|
|
int rs = gdk_pixbuf_get_rowstride (gp);
|
|
int w = gdk_pixbuf_get_width (gp);
|
|
int h = gdk_pixbuf_get_height (gp);
|
|
int x, y;
|
|
|
|
for (y = 0; y < h; y++, pixels += rs) {
|
|
guchar *p = pixels;
|
|
for (x = 0; x < w; x++, p+=4) {
|
|
if (PHSHPIXELSTOREMOVE(p))
|
|
p[3] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
get_phsh_frame (GdkPixbuf *pb, int frame)
|
|
{
|
|
GdkPixbuf *newpb;
|
|
|
|
newpb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
|
|
PHSHWIDTH, PHSHHEIGHT);
|
|
gdk_pixbuf_copy_area (pb, frame * PHSHWIDTH, 0,
|
|
PHSHWIDTH, PHSHHEIGHT, newpb, 0, 0);
|
|
|
|
return newpb;
|
|
}
|
|
|
|
typedef struct {
|
|
gboolean live;
|
|
int x, y;
|
|
} InvGoat;
|
|
|
|
typedef struct {
|
|
gboolean good;
|
|
int y;
|
|
int x;
|
|
} InvShot;
|
|
|
|
|
|
static GtkWidget *geginv = NULL;
|
|
static GtkWidget *geginv_canvas = NULL;
|
|
static GtkWidget *geginv_label = NULL;
|
|
static GdkPixbuf *inv_goat1 = NULL;
|
|
static GdkPixbuf *inv_goat2 = NULL;
|
|
static GdkPixbuf *inv_phsh1 = NULL;
|
|
static GdkPixbuf *inv_phsh2 = NULL;
|
|
static int inv_phsh_state = 0;
|
|
static int inv_goat_state = 0;
|
|
static int inv_width = 0;
|
|
static int inv_height = 0;
|
|
static int inv_goat_width = 0;
|
|
static int inv_goat_height = 0;
|
|
static int inv_phsh_width = 0;
|
|
static int inv_phsh_height = 0;
|
|
#define INV_ROWS 3
|
|
#define INV_COLS 5
|
|
static InvGoat invs[INV_COLS][INV_ROWS] = { { { FALSE, 0, 0 } } };
|
|
static int inv_num = INV_ROWS * INV_COLS;
|
|
static double inv_factor = 1.0;
|
|
static int inv_our_x = 0;
|
|
static int inv_x = 0;
|
|
static int inv_y = 0;
|
|
static int inv_first_col = 0;
|
|
static int inv_last_col = INV_COLS-1;
|
|
static int inv_level = 0;
|
|
static int inv_lives = 0;
|
|
static gboolean inv_do_pause = FALSE;
|
|
static gboolean inv_reverse = FALSE;
|
|
static gboolean inv_game_over = FALSE;
|
|
static gboolean inv_left_pressed = FALSE;
|
|
static gboolean inv_right_pressed = FALSE;
|
|
static gboolean inv_fire_pressed = FALSE;
|
|
static gboolean inv_left_released = FALSE;
|
|
static gboolean inv_right_released = FALSE;
|
|
static gboolean inv_fire_released = FALSE;
|
|
static gboolean inv_paused = FALSE;
|
|
static GSList *inv_shots = NULL;
|
|
static guint inv_draw_idle = 0;
|
|
|
|
static void
|
|
inv_show_status (void)
|
|
{
|
|
gchar *s, *t, *u, *v, *w;
|
|
if (geginv == NULL)
|
|
return;
|
|
|
|
if (inv_game_over) {
|
|
t = g_strdup_printf (_("<b>GAME OVER</b> at level %d!"),
|
|
inv_level+1);
|
|
u = g_strdup_printf ("<big>%s</big>", t);
|
|
/* Translators: the first and third strings are similar to a
|
|
* title, and the second string is a small information text.
|
|
* The spaces are there only to separate all the strings, so
|
|
try to keep them as is. */
|
|
s = g_strdup_printf (_("%1$s %2$s %3$s"),
|
|
u, _("Press 'q' to quit"), u);
|
|
g_free (t);
|
|
g_free (u);
|
|
|
|
} else if (inv_paused) {
|
|
t = g_strdup_printf("<big><b>%s</b></big>", _("Paused"));
|
|
/* Translators: the first string is a title and the second
|
|
* string is a small information text. */
|
|
s = g_strdup_printf (_("%1$s\t%2$s"),
|
|
t, _("Press 'p' to unpause"));
|
|
g_free (t);
|
|
|
|
} else {
|
|
t = g_strdup_printf ("<b>%d</b>", inv_level+1);
|
|
u = g_strdup_printf ("<b>%d</b>", inv_lives);
|
|
v = g_strdup_printf (_("Level: %s, Lives: %s"), t, u);
|
|
w = g_strdup_printf ("<big>%s</big>", v);
|
|
/* Translators: the first string is a title and the second
|
|
* string is a small information text. */
|
|
s = g_strdup_printf (_("%1$s\t%2$s"), w,
|
|
_("Left/Right to move, Space to fire, 'p' to pause, 'q' to quit"));
|
|
g_free (t);
|
|
g_free (u);
|
|
g_free (v);
|
|
g_free (w);
|
|
|
|
}
|
|
gtk_label_set_markup (GTK_LABEL (geginv_label), s);
|
|
|
|
g_free (s);
|
|
}
|
|
|
|
static gboolean
|
|
inv_queue_draw_idle (gpointer data)
|
|
{
|
|
inv_draw_idle = 0;
|
|
|
|
if (geginv)
|
|
gtk_widget_queue_draw (data);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
inv_queue_draw (GtkWidget *window)
|
|
{
|
|
if (inv_draw_idle == 0)
|
|
inv_draw_idle = g_idle_add (inv_queue_draw_idle, window);
|
|
}
|
|
|
|
static void
|
|
inv_draw_explosion (int x, int y)
|
|
{
|
|
GdkDrawingContext *context;
|
|
cairo_rectangle_int_t rect;
|
|
cairo_region_t *region;
|
|
cairo_t *cr;
|
|
int i;
|
|
|
|
if ( ! gtk_widget_is_drawable (geginv_canvas))
|
|
return;
|
|
|
|
rect.x = x - 100;
|
|
rect.y = y - 100;
|
|
rect.width = 200;
|
|
rect.height = 200;
|
|
|
|
region = cairo_region_create_rectangle (&rect);
|
|
context = gdk_window_begin_draw_frame (gtk_widget_get_window (geginv_canvas),
|
|
region);
|
|
cairo_region_destroy (region);
|
|
|
|
cr = gdk_drawing_context_get_cairo_context (context);
|
|
|
|
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
|
|
|
|
for (i = 5; i < 100; i += 5) {
|
|
cairo_arc (cr, x, y, i, 0, 2 * G_PI);
|
|
cairo_fill (cr);
|
|
gdk_display_flush (gtk_widget_get_display (geginv_canvas));
|
|
g_usleep (50000);
|
|
}
|
|
|
|
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
|
|
|
for (i = 5; i < 100; i += 5) {
|
|
cairo_arc (cr, x, y, i, 0, 2 * G_PI);
|
|
cairo_fill (cr);
|
|
gdk_display_flush (gtk_widget_get_display (geginv_canvas));
|
|
g_usleep (50000);
|
|
}
|
|
|
|
gdk_window_end_draw_frame (gtk_widget_get_window (geginv_canvas),
|
|
context);
|
|
|
|
inv_queue_draw (geginv);
|
|
}
|
|
|
|
|
|
static void
|
|
inv_do_game_over (void)
|
|
{
|
|
GSList *li;
|
|
|
|
inv_game_over = TRUE;
|
|
|
|
for (li = inv_shots; li != NULL; li = li->next) {
|
|
InvShot *shot = li->data;
|
|
shot->good = FALSE;
|
|
}
|
|
|
|
inv_queue_draw (geginv);
|
|
|
|
inv_show_status ();
|
|
}
|
|
|
|
|
|
static GdkPixbuf *
|
|
pb_scale (GdkPixbuf *pb, double scale)
|
|
{
|
|
int w, h;
|
|
|
|
if (scale == 1.0)
|
|
return (GdkPixbuf *)g_object_ref ((GObject *)pb);
|
|
|
|
w = gdk_pixbuf_get_width (pb) * scale;
|
|
h = gdk_pixbuf_get_height (pb) * scale;
|
|
|
|
return gdk_pixbuf_scale_simple (pb, w, h,
|
|
GDK_INTERP_BILINEAR);
|
|
}
|
|
|
|
static void
|
|
refind_first_and_last (void)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < INV_COLS; i++) {
|
|
gboolean all_null = TRUE;
|
|
for (j = 0; j < INV_ROWS; j++) {
|
|
if (invs[i][j].live) {
|
|
all_null = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if ( ! all_null) {
|
|
inv_first_col = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = INV_COLS-1; i >= 0; i--) {
|
|
gboolean all_null = TRUE;
|
|
for (j = 0; j < INV_ROWS; j++) {
|
|
if (invs[i][j].live) {
|
|
all_null = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if ( ! all_null) {
|
|
inv_last_col = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
whack_gegl (int i, int j)
|
|
{
|
|
if ( ! invs[i][j].live)
|
|
return;
|
|
|
|
invs[i][j].live = FALSE;
|
|
inv_num --;
|
|
|
|
if (inv_num > 0) {
|
|
refind_first_and_last ();
|
|
} else {
|
|
inv_x = 70;
|
|
inv_y = 70;
|
|
inv_first_col = 0;
|
|
inv_last_col = INV_COLS-1;
|
|
inv_reverse = FALSE;
|
|
|
|
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
|
|
g_slist_free (inv_shots);
|
|
inv_shots = NULL;
|
|
|
|
for (i = 0; i < INV_COLS; i++) {
|
|
for (j = 0; j < INV_ROWS; j++) {
|
|
invs[i][j].live = TRUE;
|
|
invs[i][j].x = 70 + i * 100;
|
|
invs[i][j].y = 70 + j * 80;
|
|
}
|
|
}
|
|
inv_num = INV_ROWS * INV_COLS;
|
|
|
|
inv_level ++;
|
|
|
|
inv_show_status ();
|
|
}
|
|
|
|
inv_queue_draw (geginv);
|
|
}
|
|
|
|
static gboolean
|
|
geginv_timeout (gpointer data)
|
|
{
|
|
int i, j;
|
|
int limitx1;
|
|
int limitx2;
|
|
int speed;
|
|
int shots;
|
|
int max_shots;
|
|
|
|
if (inv_paused)
|
|
return TRUE;
|
|
|
|
if (geginv != data ||
|
|
inv_num <= 0 ||
|
|
inv_y > 700)
|
|
return FALSE;
|
|
|
|
limitx1 = 70 - (inv_first_col * 100);
|
|
limitx2 = 800 - 70 - (inv_last_col * 100);
|
|
|
|
if (inv_game_over) {
|
|
inv_y += 30;
|
|
} else {
|
|
if (inv_num < (INV_COLS*INV_ROWS)/3)
|
|
speed = 45+2*inv_level;
|
|
else if (inv_num < (2*INV_COLS*INV_ROWS)/3)
|
|
speed = 30+2*inv_level;
|
|
else
|
|
speed = 15+2*inv_level;
|
|
|
|
if (inv_reverse) {
|
|
inv_x -= speed;
|
|
if (inv_x < limitx1) {
|
|
inv_reverse = FALSE;
|
|
inv_x = (limitx1 + (limitx1 - inv_x));
|
|
inv_y += 30+inv_level;
|
|
}
|
|
} else {
|
|
inv_x += speed;
|
|
if (inv_x > limitx2) {
|
|
inv_reverse = TRUE;
|
|
inv_x = (limitx2 - (inv_x - limitx2));
|
|
inv_y += 30+inv_level;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < INV_COLS; i++) {
|
|
for (j = 0; j < INV_ROWS; j++) {
|
|
if (invs[i][j].live) {
|
|
invs[i][j].x = inv_x + i * 100;
|
|
invs[i][j].y = inv_y + j * 80;
|
|
|
|
if ( ! inv_game_over &&
|
|
invs[i][j].y >= 570) {
|
|
inv_do_game_over ();
|
|
} else if ( ! inv_game_over &&
|
|
invs[i][j].y >= 530 &&
|
|
invs[i][j].x + 40 > inv_our_x - 25 &&
|
|
invs[i][j].x - 40 < inv_our_x + 25) {
|
|
whack_gegl (i,j);
|
|
inv_lives --;
|
|
inv_draw_explosion (inv_our_x, 550);
|
|
if (inv_lives <= 0) {
|
|
inv_do_game_over ();
|
|
} else {
|
|
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
|
|
g_slist_free (inv_shots);
|
|
inv_shots = NULL;
|
|
inv_our_x = 400;
|
|
inv_do_pause = TRUE;
|
|
inv_show_status ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
shots = 0;
|
|
max_shots = (g_random_int () >> 3) % (2+inv_level);
|
|
while ( ! inv_game_over && shots < MIN (max_shots, inv_num)) {
|
|
int i = (g_random_int () >> 3) % INV_COLS;
|
|
for (j = INV_ROWS-1; j >= 0; j--) {
|
|
if (invs[i][j].live) {
|
|
InvShot *shot = g_new0 (InvShot, 1);
|
|
|
|
shot->good = FALSE;
|
|
shot->x = invs[i][j].x + (g_random_int () % 6) - 3;
|
|
shot->y = invs[i][j].y + inv_goat_height/2 + (g_random_int () % 3);
|
|
|
|
inv_shots = g_slist_prepend (inv_shots, shot);
|
|
shots++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
inv_goat_state = (inv_goat_state+1) % 2;
|
|
|
|
inv_queue_draw (geginv);
|
|
|
|
g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
find_gegls (int x, int y)
|
|
{
|
|
int i, j;
|
|
|
|
/* FIXME: this is stupid, we can do better */
|
|
for (i = 0; i < INV_COLS; i++) {
|
|
for (j = 0; j < INV_ROWS; j++) {
|
|
int ix = invs[i][j].x;
|
|
int iy = invs[i][j].y;
|
|
|
|
if ( ! invs[i][j].live)
|
|
continue;
|
|
|
|
if (y >= iy - 30 &&
|
|
y <= iy + 30 &&
|
|
x >= ix - 40 &&
|
|
x <= ix + 40) {
|
|
whack_gegl (i, j);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
geginv_move_timeout (gpointer data)
|
|
{
|
|
GSList *li;
|
|
static int shot_inhibit = 0;
|
|
|
|
if (inv_paused)
|
|
return TRUE;
|
|
|
|
if (geginv != data ||
|
|
inv_num <= 0 ||
|
|
inv_y > 700)
|
|
return FALSE;
|
|
|
|
inv_phsh_state = (inv_phsh_state+1)%10;
|
|
|
|
/* we will be drawing something */
|
|
if (inv_shots != NULL)
|
|
inv_queue_draw (geginv);
|
|
|
|
li = inv_shots;
|
|
while (li != NULL) {
|
|
InvShot *shot = li->data;
|
|
|
|
if (shot->good) {
|
|
shot->y -= 30;
|
|
if (find_gegls (shot->x, shot->y) ||
|
|
shot->y <= 0) {
|
|
GSList *list = li;
|
|
/* we were restarted */
|
|
if (inv_shots == NULL)
|
|
return TRUE;
|
|
li = li->next;
|
|
g_free (shot);
|
|
inv_shots = g_slist_delete_link (inv_shots, list);
|
|
continue;
|
|
}
|
|
} else /* bad */ {
|
|
shot->y += 30;
|
|
if ( ! inv_game_over &&
|
|
shot->y >= 535 &&
|
|
shot->y <= 565 &&
|
|
shot->x >= inv_our_x - 25 &&
|
|
shot->x <= inv_our_x + 25) {
|
|
inv_lives --;
|
|
inv_draw_explosion (inv_our_x, 550);
|
|
if (inv_lives <= 0) {
|
|
inv_do_game_over ();
|
|
} else {
|
|
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
|
|
g_slist_free (inv_shots);
|
|
inv_shots = NULL;
|
|
inv_our_x = 400;
|
|
inv_do_pause = TRUE;
|
|
inv_show_status ();
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (shot->y >= 600) {
|
|
GSList *list = li;
|
|
li = li->next;
|
|
g_free (shot);
|
|
inv_shots = g_slist_delete_link (inv_shots, list);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
li = li->next;
|
|
}
|
|
|
|
if ( ! inv_game_over) {
|
|
if (inv_left_pressed && inv_our_x > 100) {
|
|
inv_our_x -= 20;
|
|
inv_queue_draw (geginv);
|
|
} else if (inv_right_pressed && inv_our_x < 700) {
|
|
inv_our_x += 20;
|
|
inv_queue_draw (geginv);
|
|
}
|
|
}
|
|
|
|
if (shot_inhibit > 0)
|
|
shot_inhibit--;
|
|
|
|
if ( ! inv_game_over && inv_fire_pressed && shot_inhibit == 0) {
|
|
InvShot *shot = g_new0 (InvShot, 1);
|
|
|
|
shot->good = TRUE;
|
|
shot->x = inv_our_x;
|
|
shot->y = 540;
|
|
|
|
inv_shots = g_slist_prepend (inv_shots, shot);
|
|
|
|
shot_inhibit = 5;
|
|
|
|
inv_queue_draw (geginv);
|
|
}
|
|
|
|
if (inv_left_released)
|
|
inv_left_pressed = FALSE;
|
|
if (inv_right_released)
|
|
inv_right_pressed = FALSE;
|
|
if (inv_fire_released)
|
|
inv_fire_pressed = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
inv_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
|
|
{
|
|
switch (event->keyval) {
|
|
case GDK_KEY_Left:
|
|
case GDK_KEY_KP_Left:
|
|
case GDK_KEY_Pointer_Left:
|
|
inv_left_pressed = TRUE;
|
|
inv_left_released = FALSE;
|
|
return TRUE;
|
|
case GDK_KEY_Right:
|
|
case GDK_KEY_KP_Right:
|
|
case GDK_KEY_Pointer_Right:
|
|
inv_right_pressed = TRUE;
|
|
inv_right_released = FALSE;
|
|
return TRUE;
|
|
case GDK_KEY_space:
|
|
case GDK_KEY_KP_Space:
|
|
inv_fire_pressed = TRUE;
|
|
inv_fire_released = FALSE;
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
inv_key_release (GtkWidget *widget, GdkEventKey *event, gpointer data)
|
|
{
|
|
switch (event->keyval) {
|
|
case GDK_KEY_Left:
|
|
case GDK_KEY_KP_Left:
|
|
case GDK_KEY_Pointer_Left:
|
|
inv_left_released = TRUE;
|
|
return TRUE;
|
|
case GDK_KEY_Right:
|
|
case GDK_KEY_KP_Right:
|
|
case GDK_KEY_Pointer_Right:
|
|
inv_right_released = TRUE;
|
|
return TRUE;
|
|
case GDK_KEY_space:
|
|
case GDK_KEY_KP_Space:
|
|
inv_fire_released = TRUE;
|
|
return TRUE;
|
|
case GDK_KEY_q:
|
|
case GDK_KEY_Q:
|
|
gtk_widget_destroy (widget);
|
|
return TRUE;
|
|
case GDK_KEY_p:
|
|
case GDK_KEY_P:
|
|
inv_paused = ! inv_paused;
|
|
inv_show_status ();
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
ensure_creatures (void)
|
|
{
|
|
GdkPixbuf *pb, *pb1;
|
|
|
|
if (inv_goat1 != NULL)
|
|
return TRUE;
|
|
|
|
pb = gdk_pixbuf_new_from_resource ("/technology.heckin/lebl-dialog/wanda.png",
|
|
NULL);
|
|
if (pb == NULL)
|
|
return FALSE;
|
|
|
|
pb1 = get_phsh_frame (pb, 1);
|
|
inv_phsh1 = pb_scale (pb1, inv_factor);
|
|
g_object_unref (G_OBJECT (pb1));
|
|
phsh_unsea (inv_phsh1);
|
|
|
|
pb1 = get_phsh_frame (pb, 2);
|
|
inv_phsh2 = pb_scale (pb1, inv_factor);
|
|
g_object_unref (G_OBJECT (pb1));
|
|
phsh_unsea (inv_phsh2);
|
|
|
|
g_object_unref (G_OBJECT (pb));
|
|
|
|
pb = gdk_pixbuf_new_from_resource ("/technology.heckin/lebl-dialog/gegl-1.png",
|
|
NULL);
|
|
if (pb == NULL) {
|
|
g_object_unref (G_OBJECT (inv_phsh1));
|
|
g_object_unref (G_OBJECT (inv_phsh2));
|
|
return FALSE;
|
|
}
|
|
|
|
inv_goat1 = pb_scale (pb, inv_factor * 0.66);
|
|
g_object_unref (pb);
|
|
|
|
pb = gdk_pixbuf_new_from_resource ("/technology.heckin/lebl-dialog/gegl-2.png",
|
|
NULL);
|
|
if (pb == NULL) {
|
|
g_object_unref (G_OBJECT (inv_goat1));
|
|
g_object_unref (G_OBJECT (inv_phsh1));
|
|
g_object_unref (G_OBJECT (inv_phsh2));
|
|
return FALSE;
|
|
}
|
|
|
|
inv_goat2 = pb_scale (pb, inv_factor * 0.66);
|
|
g_object_unref (pb);
|
|
|
|
inv_goat_width = gdk_pixbuf_get_width (inv_goat1);
|
|
inv_goat_height = gdk_pixbuf_get_height (inv_goat1);
|
|
inv_phsh_width = gdk_pixbuf_get_width (inv_phsh1);
|
|
inv_phsh_height = gdk_pixbuf_get_height (inv_phsh1);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
geginv_destroyed (GtkWidget *w, gpointer data)
|
|
{
|
|
geginv = NULL;
|
|
}
|
|
|
|
static gboolean
|
|
inv_draw (GtkWidget *widget, cairo_t *cr)
|
|
{
|
|
GdkPixbuf *goat;
|
|
GSList *li;
|
|
int i, j;
|
|
|
|
if (geginv == NULL) {
|
|
inv_draw_idle = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
|
cairo_paint (cr);
|
|
|
|
if (inv_goat_state == 0)
|
|
goat = inv_goat1;
|
|
else
|
|
goat = inv_goat2;
|
|
|
|
for (i = 0; i < INV_COLS; i++) {
|
|
for (j = 0; j < INV_ROWS; j++) {
|
|
int x, y;
|
|
if ( ! invs[i][j].live)
|
|
continue;
|
|
|
|
x = invs[i][j].x*inv_factor - inv_goat_width/2,
|
|
y = invs[i][j].y*inv_factor - inv_goat_height/2,
|
|
|
|
gdk_cairo_set_source_pixbuf (cr, goat, x, y);
|
|
cairo_rectangle (cr,
|
|
x, y,
|
|
inv_goat_width,
|
|
inv_goat_height);
|
|
cairo_fill (cr);
|
|
}
|
|
}
|
|
|
|
for (li = inv_shots; li != NULL; li = li->next) {
|
|
InvShot *shot = li->data;
|
|
|
|
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
|
cairo_rectangle (cr,
|
|
(shot->x-1)*inv_factor,
|
|
(shot->y-4)*inv_factor,
|
|
3, 8);
|
|
cairo_fill (cr);
|
|
}
|
|
|
|
if ( ! inv_game_over) {
|
|
GdkPixbuf *phsh;
|
|
|
|
if (inv_phsh_state < 5) {
|
|
phsh = inv_phsh1;
|
|
} else {
|
|
phsh = inv_phsh2;
|
|
}
|
|
|
|
gdk_cairo_set_source_pixbuf (cr, phsh,
|
|
inv_our_x*inv_factor - inv_phsh_width/2,
|
|
550*inv_factor - inv_phsh_height/2);
|
|
cairo_rectangle (cr,
|
|
inv_our_x*inv_factor - inv_phsh_width/2,
|
|
550*inv_factor - inv_phsh_height/2,
|
|
inv_phsh_width,
|
|
inv_phsh_height);
|
|
cairo_fill (cr);
|
|
}
|
|
|
|
if (inv_do_pause) {
|
|
g_usleep (G_USEC_PER_SEC);
|
|
inv_do_pause = FALSE;
|
|
}
|
|
|
|
inv_draw_idle = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean pika_lebl_dialog (void);
|
|
|
|
gboolean
|
|
pika_lebl_dialog (void)
|
|
{
|
|
GdkMonitor *monitor;
|
|
GdkRectangle workarea;
|
|
GtkWidget *vbox;
|
|
int i, j;
|
|
|
|
if (geginv != NULL) {
|
|
gtk_window_present (GTK_WINDOW (geginv));
|
|
return FALSE;
|
|
}
|
|
|
|
inv_width = 800;
|
|
inv_height = 600;
|
|
|
|
monitor = pika_get_monitor_at_pointer ();
|
|
gdk_monitor_get_workarea (monitor, &workarea);
|
|
|
|
if (inv_width > workarea.width * 0.9) {
|
|
inv_width = workarea.width * 0.9;
|
|
inv_height = inv_width * (600.0/800.0);
|
|
}
|
|
|
|
if (inv_height > workarea.height * 0.9) {
|
|
inv_height = workarea.height * 0.9;
|
|
inv_width = inv_height * (800.0/600.0);
|
|
}
|
|
|
|
inv_factor = (double)inv_width / 800.0;
|
|
|
|
if ( ! ensure_creatures ())
|
|
return FALSE;
|
|
|
|
geginv = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_position (GTK_WINDOW (geginv), GTK_WIN_POS_CENTER);
|
|
gtk_window_set_title (GTK_WINDOW (geginv), _("Killer GEGLs from Outer Space"));
|
|
g_object_set (G_OBJECT (geginv), "resizable", FALSE, NULL);
|
|
g_signal_connect (G_OBJECT (geginv), "destroy",
|
|
G_CALLBACK (geginv_destroyed),
|
|
NULL);
|
|
|
|
geginv_canvas = gtk_drawing_area_new ();
|
|
gtk_widget_set_size_request (geginv_canvas, inv_width, inv_height);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_container_add (GTK_CONTAINER (geginv), vbox);
|
|
gtk_box_pack_start (GTK_BOX (vbox), geginv_canvas, TRUE, TRUE, 0);
|
|
|
|
geginv_label = gtk_label_new ("");
|
|
gtk_box_pack_start (GTK_BOX (vbox), geginv_label, FALSE, FALSE, 0);
|
|
|
|
inv_our_x = 400;
|
|
inv_x = 70;
|
|
inv_y = 70;
|
|
inv_first_col = 0;
|
|
inv_level = 0;
|
|
inv_lives = 3;
|
|
inv_last_col = INV_COLS-1;
|
|
inv_reverse = FALSE;
|
|
inv_game_over = FALSE;
|
|
inv_left_pressed = FALSE;
|
|
inv_right_pressed = FALSE;
|
|
inv_fire_pressed = FALSE;
|
|
inv_left_released = FALSE;
|
|
inv_right_released = FALSE;
|
|
inv_fire_released = FALSE;
|
|
inv_paused = FALSE;
|
|
|
|
gtk_widget_add_events (geginv, GDK_KEY_RELEASE_MASK);
|
|
|
|
g_signal_connect (G_OBJECT (geginv), "key_press_event",
|
|
G_CALLBACK (inv_key_press), NULL);
|
|
g_signal_connect (G_OBJECT (geginv), "key_release_event",
|
|
G_CALLBACK (inv_key_release), NULL);
|
|
g_signal_connect (G_OBJECT (geginv_canvas), "draw",
|
|
G_CALLBACK (inv_draw), NULL);
|
|
|
|
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
|
|
g_slist_free (inv_shots);
|
|
inv_shots = NULL;
|
|
|
|
for (i = 0; i < INV_COLS; i++) {
|
|
for (j = 0; j < INV_ROWS; j++) {
|
|
invs[i][j].live = TRUE;
|
|
invs[i][j].x = 70 + i * 100;
|
|
invs[i][j].y = 70 + j * 80;
|
|
}
|
|
}
|
|
inv_num = INV_ROWS * INV_COLS;
|
|
|
|
g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv);
|
|
g_timeout_add (90, geginv_move_timeout, geginv);
|
|
|
|
inv_show_status ();
|
|
|
|
gtk_widget_show_all (geginv);
|
|
return FALSE;
|
|
}
|