[gnome-robots] Rewrite graphics module in Vala



commit 290726c383096a6e2c72158f7114ac5efa8b0055
Author: Andrey Kutejko <andy128k gmail com>
Date:   Wed Aug 26 00:57:13 2020 +0200

    Rewrite graphics module in Vala

 src/game.c          | 139 ++++++------
 src/gbdefs.h        |  46 ----
 src/gnome-robots.c  |  22 +-
 src/graphics.c      | 611 ----------------------------------------------------
 src/graphics.h      |  35 ---
 src/graphics.vala   | 459 +++++++++++++++++++++++++++++++++++++++
 src/keyboard.c      |   1 +
 src/main.vapi       |   7 +-
 src/meson.build     |   2 +-
 src/properties.vala |   6 +-
 10 files changed, 558 insertions(+), 770 deletions(-)
---
diff --git a/src/game.c b/src/game.c
index 1e2be47..224120d 100644
--- a/src/game.c
+++ b/src/game.c
@@ -32,7 +32,6 @@
 #include "keyboard.h"
 #include "game.h"
 #include "gnome-robots.h"
-#include "graphics.h"
 
 /**********************************************************************/
 /* Exported Variables                                                 */
@@ -183,7 +182,7 @@ kill_player (void)
 {
   game_state = STATE_DEAD;
   play_sound (SOUND_DIE);
-  arena[player_xpos][player_ypos] = OBJECT_PLAYER;
+  arena[player_xpos][player_ypos] = OBJECT_TYPE_PLAYER;
   endlev_counter = 0;
   add_aieee_bubble (player_xpos, player_ypos);
   player_animation_dead ();
@@ -206,7 +205,7 @@ add_kill (gint type)
   game_configs_get_current (game_configs, &game_config);
 
   if ((game_state == STATE_WAITING) || (game_state == STATE_WTYPE2)) {
-    if (type == OBJECT_ROBOT1) {
+    if (type == OBJECT_TYPE_ROBOT1) {
       si = game_config.score_type1_waiting;
       kills += 1;
     } else {
@@ -214,7 +213,7 @@ add_kill (gint type)
       kills += 2;
     }
   } else {
-    if (type == OBJECT_ROBOT1) {
+    if (type == OBJECT_TYPE_ROBOT1) {
       si = game_config.score_type1;
     } else {
       si = game_config.score_type2;
@@ -259,7 +258,7 @@ clear_arena (void)
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      arena[i][j] = OBJECT_NONE;
+      arena[i][j] = OBJECT_TYPE_NONE;
     }
   }
 
@@ -281,10 +280,10 @@ load_temp_arena (void)
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if (arena[i][j] != OBJECT_PLAYER) {
+      if (arena[i][j] != OBJECT_TYPE_PLAYER) {
         temp_arena[i][j] = arena[i][j];
       } else {
-        temp_arena[i][j] = OBJECT_NONE;
+        temp_arena[i][j] = OBJECT_TYPE_NONE;
       }
     }
   }
@@ -299,13 +298,13 @@ load_temp_arena (void)
  * checks for an object at a given location
  *
  * Returns:
- * type of object if present or OBJECT_NONE
+ * type of object if present or OBJECT_TYPE_NONE
  **/
 static gint
 check_location (gint x, gint y)
 {
   if ((x < 0) || (y < 0) || (x >= GAME_WIDTH) || (y >= GAME_HEIGHT)) {
-    return OBJECT_NONE;
+    return OBJECT_TYPE_NONE;
   }
 
   return arena[x][y];
@@ -328,7 +327,7 @@ generate_level (void)
 
   clear_arena ();
 
-  arena[PLAYER_DEF_XPOS][PLAYER_DEF_YPOS] = OBJECT_PLAYER;
+  arena[PLAYER_DEF_XPOS][PLAYER_DEF_YPOS] = OBJECT_TYPE_PLAYER;
   player_xpos = PLAYER_DEF_XPOS;
   player_ypos = PLAYER_DEF_YPOS;
 
@@ -373,8 +372,8 @@ generate_level (void)
       xp = rand () % GAME_WIDTH;
       yp = rand () % GAME_HEIGHT;
 
-      if (check_location (xp, yp) == OBJECT_NONE) {
-        arena[xp][yp] = OBJECT_ROBOT1;
+      if (check_location (xp, yp) == OBJECT_TYPE_NONE) {
+        arena[xp][yp] = OBJECT_TYPE_ROBOT1;
         break;
       }
     }
@@ -386,8 +385,8 @@ generate_level (void)
       xp = rand () % GAME_WIDTH;
       yp = rand () % GAME_HEIGHT;
 
-      if (check_location (xp, yp) == OBJECT_NONE) {
-        arena[xp][yp] = OBJECT_ROBOT2;
+      if (check_location (xp, yp) == OBJECT_TYPE_NONE) {
+        arena[xp][yp] = OBJECT_TYPE_ROBOT2;
         break;
       }
     }
@@ -416,15 +415,15 @@ update_arena (void)
     for (j = 0; j < GAME_HEIGHT; ++j) {
 
 
-      if ((temp_arena[i][j] == OBJECT_HEAP) &&
+      if ((temp_arena[i][j] == OBJECT_TYPE_HEAP) &&
           (push_xpos == i) && (push_ypos == j)) {
-        if (arena[i][j] == OBJECT_ROBOT1) {
+        if (arena[i][j] == OBJECT_TYPE_ROBOT1) {
           add_splat_bubble (i, j);
           play_sound (SOUND_SPLAT);
           push_xpos = push_ypos = -1;
           score += game_config.score_type1_splatted;
         }
-        if (arena[i][j] == OBJECT_ROBOT2) {
+        if (arena[i][j] == OBJECT_TYPE_ROBOT2) {
           add_splat_bubble (i, j);
           play_sound (SOUND_SPLAT);
           push_xpos = push_ypos = -1;
@@ -434,15 +433,15 @@ update_arena (void)
 
 
       arena[i][j] = temp_arena[i][j];
-      if (arena[i][j] == OBJECT_ROBOT1) {
+      if (arena[i][j] == OBJECT_TYPE_ROBOT1) {
         num_robots1 += 1;
-      } else if (arena[i][j] == OBJECT_ROBOT2) {
+      } else if (arena[i][j] == OBJECT_TYPE_ROBOT2) {
         num_robots2 += 1;
       }
     }
   }
 
-  if (arena[player_xpos][player_ypos] != OBJECT_PLAYER) {
+  if (arena[player_xpos][player_ypos] != OBJECT_TYPE_PLAYER) {
     kill_player ();
   } else {
     /* This is in the else statement to catch the case where the last
@@ -630,17 +629,17 @@ move_all_robots (void)
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if ((arena[i][j] == OBJECT_PLAYER) || (arena[i][j] == OBJECT_HEAP)) {
+      if ((arena[i][j] == OBJECT_TYPE_PLAYER) || (arena[i][j] == OBJECT_TYPE_HEAP)) {
         temp_arena[i][j] = arena[i][j];
       } else {
-        temp_arena[i][j] = OBJECT_NONE;
+        temp_arena[i][j] = OBJECT_TYPE_NONE;
       }
     }
   }
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if ((arena[i][j] == OBJECT_ROBOT1) || (arena[i][j] == OBJECT_ROBOT2)) {
+      if ((arena[i][j] == OBJECT_TYPE_ROBOT1) || (arena[i][j] == OBJECT_TYPE_ROBOT2)) {
         nx = i;
         ny = j;
         if (player_xpos < nx)
@@ -652,13 +651,13 @@ move_all_robots (void)
         if (player_ypos > ny)
           ny += 1;
 
-        if (temp_arena[nx][ny] == OBJECT_HEAP) {
+        if (temp_arena[nx][ny] == OBJECT_TYPE_HEAP) {
           add_kill (arena[i][j]);
-        } else if ((temp_arena[nx][ny] == OBJECT_ROBOT1) ||
-                   (temp_arena[nx][ny] == OBJECT_ROBOT2)) {
+        } else if ((temp_arena[nx][ny] == OBJECT_TYPE_ROBOT1) ||
+                   (temp_arena[nx][ny] == OBJECT_TYPE_ROBOT2)) {
           add_kill (arena[i][j]);
           add_kill (temp_arena[nx][ny]);
-          temp_arena[nx][ny] = OBJECT_HEAP;
+          temp_arena[nx][ny] = OBJECT_TYPE_HEAP;
         } else {
           temp_arena[nx][ny] = arena[i][j];
         }
@@ -683,18 +682,18 @@ move_type2_robots (void)
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if ((arena[i][j] == OBJECT_PLAYER) ||
-          (arena[i][j] == OBJECT_ROBOT1) || (arena[i][j] == OBJECT_HEAP)) {
+      if ((arena[i][j] == OBJECT_TYPE_PLAYER) ||
+          (arena[i][j] == OBJECT_TYPE_ROBOT1) || (arena[i][j] == OBJECT_TYPE_HEAP)) {
         temp_arena[i][j] = arena[i][j];
       } else {
-        temp_arena[i][j] = OBJECT_NONE;
+        temp_arena[i][j] = OBJECT_TYPE_NONE;
       }
     }
   }
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if (arena[i][j] == OBJECT_ROBOT2) {
+      if (arena[i][j] == OBJECT_TYPE_ROBOT2) {
         nx = i;
         ny = j;
         if (player_xpos < nx)
@@ -706,13 +705,13 @@ move_type2_robots (void)
         if (player_ypos > ny)
           ny += 1;
 
-        if (temp_arena[nx][ny] == OBJECT_HEAP) {
+        if (temp_arena[nx][ny] == OBJECT_TYPE_HEAP) {
           add_kill (arena[i][j]);
-        } else if ((temp_arena[nx][ny] == OBJECT_ROBOT1) ||
-                   (temp_arena[nx][ny] == OBJECT_ROBOT2)) {
+        } else if ((temp_arena[nx][ny] == OBJECT_TYPE_ROBOT1) ||
+                   (temp_arena[nx][ny] == OBJECT_TYPE_ROBOT2)) {
           add_kill (arena[i][j]);
           add_kill (temp_arena[nx][ny]);
-          temp_arena[nx][ny] = OBJECT_HEAP;
+          temp_arena[nx][ny] = OBJECT_TYPE_HEAP;
         } else {
           temp_arena[nx][ny] = arena[i][j];
         }
@@ -765,24 +764,24 @@ check_safe (gint x, gint y)
   gint i, j;
   gint nx, ny;
 
-  if (temp_arena[x][y] != OBJECT_NONE)
+  if (temp_arena[x][y] != OBJECT_TYPE_NONE)
     return FALSE;
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if ((temp_arena[i][j] == OBJECT_PLAYER) ||
-          (temp_arena[i][j] == OBJECT_HEAP)) {
+      if ((temp_arena[i][j] == OBJECT_TYPE_PLAYER) ||
+          (temp_arena[i][j] == OBJECT_TYPE_HEAP)) {
         temp2_arena[i][j] = temp_arena[i][j];
       } else {
-        temp2_arena[i][j] = OBJECT_NONE;
+        temp2_arena[i][j] = OBJECT_TYPE_NONE;
       }
     }
   }
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if ((temp_arena[i][j] == OBJECT_ROBOT1) ||
-          (temp_arena[i][j] == OBJECT_ROBOT2)) {
+      if ((temp_arena[i][j] == OBJECT_TYPE_ROBOT1) ||
+          (temp_arena[i][j] == OBJECT_TYPE_ROBOT2)) {
         nx = i;
         ny = j;
         if (x < nx)
@@ -794,10 +793,10 @@ check_safe (gint x, gint y)
         if (y > ny)
           ny += 1;
 
-        if ((temp2_arena[nx][ny] == OBJECT_ROBOT1) ||
-            (temp2_arena[nx][ny] == OBJECT_ROBOT2) ||
-            (temp2_arena[nx][ny] == OBJECT_HEAP)) {
-          temp2_arena[nx][ny] = OBJECT_HEAP;
+        if ((temp2_arena[nx][ny] == OBJECT_TYPE_ROBOT1) ||
+            (temp2_arena[nx][ny] == OBJECT_TYPE_ROBOT2) ||
+            (temp2_arena[nx][ny] == OBJECT_TYPE_HEAP)) {
+          temp2_arena[nx][ny] = OBJECT_TYPE_HEAP;
         } else {
           temp2_arena[nx][ny] = temp_arena[i][j];
         }
@@ -805,23 +804,23 @@ check_safe (gint x, gint y)
     }
   }
 
-  if (temp2_arena[x][y] != OBJECT_NONE)
+  if (temp2_arena[x][y] != OBJECT_TYPE_NONE)
     return FALSE;
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if ((temp2_arena[i][j] == OBJECT_PLAYER) ||
-          (temp2_arena[i][j] == OBJECT_HEAP)) {
+      if ((temp2_arena[i][j] == OBJECT_TYPE_PLAYER) ||
+          (temp2_arena[i][j] == OBJECT_TYPE_HEAP)) {
         temp3_arena[i][j] = temp2_arena[i][j];
       } else {
-        temp3_arena[i][j] = OBJECT_NONE;
+        temp3_arena[i][j] = OBJECT_TYPE_NONE;
       }
     }
   }
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if (temp2_arena[i][j] == OBJECT_ROBOT2) {
+      if (temp2_arena[i][j] == OBJECT_TYPE_ROBOT2) {
         nx = i;
         ny = j;
         if (x < nx)
@@ -833,10 +832,10 @@ check_safe (gint x, gint y)
         if (y > ny)
           ny += 1;
 
-        if ((temp3_arena[nx][ny] == OBJECT_ROBOT1) ||
-            (temp3_arena[nx][ny] == OBJECT_ROBOT2) ||
-            (temp3_arena[nx][ny] == OBJECT_HEAP)) {
-          temp3_arena[nx][ny] = OBJECT_HEAP;
+        if ((temp3_arena[nx][ny] == OBJECT_TYPE_ROBOT1) ||
+            (temp3_arena[nx][ny] == OBJECT_TYPE_ROBOT2) ||
+            (temp3_arena[nx][ny] == OBJECT_TYPE_HEAP)) {
+          temp3_arena[nx][ny] = OBJECT_TYPE_HEAP;
         } else {
           temp3_arena[nx][ny] = temp2_arena[i][j];
         }
@@ -844,7 +843,7 @@ check_safe (gint x, gint y)
     }
   }
 
-  if (temp3_arena[x][y] != OBJECT_NONE)
+  if (temp3_arena[x][y] != OBJECT_TYPE_NONE)
     return FALSE;
 
   return TRUE;
@@ -869,21 +868,21 @@ push_heap (gint x, gint y, gint dx, gint dy)
   gint nx = x + dx;
   gint ny = y + dy;
 
-  if (temp_arena[x][y] != OBJECT_HEAP)
+  if (temp_arena[x][y] != OBJECT_TYPE_HEAP)
     return FALSE;
 
   if ((nx < 0) || (nx >= GAME_WIDTH) || (ny < 0) || (ny >= GAME_HEIGHT)) {
     return FALSE;
   }
 
-  if (temp_arena[nx][ny] == OBJECT_HEAP)
+  if (temp_arena[nx][ny] == OBJECT_TYPE_HEAP)
     return FALSE;
 
   push_xpos = nx;
   push_ypos = ny;
 
-  temp_arena[nx][ny] = OBJECT_HEAP;
-  temp_arena[x][y] = OBJECT_NONE;
+  temp_arena[nx][ny] = OBJECT_TYPE_HEAP;
+  temp_arena[x][y] = OBJECT_TYPE_NONE;
 
   return TRUE;
 }
@@ -917,7 +916,7 @@ try_player_move (gint dx, gint dy)
 
   load_temp_arena ();
 
-  if (temp_arena[nx][ny] == OBJECT_HEAP) {
+  if (temp_arena[nx][ny] == OBJECT_TYPE_HEAP) {
     if (game_config.moveable_heaps) {
       if (!push_heap (nx, ny, dx, dy)) {
         push_xpos = push_ypos = -1;
@@ -1062,8 +1061,8 @@ player_move (gint dx, gint dy)
   player_xpos = nx;
   player_ypos = ny;
 
-  if (temp_arena[player_xpos][player_ypos] == OBJECT_NONE) {
-    temp_arena[player_xpos][player_ypos] = OBJECT_PLAYER;
+  if (temp_arena[player_xpos][player_ypos] == OBJECT_TYPE_NONE) {
+    temp_arena[player_xpos][player_ypos] = OBJECT_TYPE_PLAYER;
   }
 
   reset_player_animation ();
@@ -1093,10 +1092,10 @@ random_teleport (void)
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if (arena[i][j] != OBJECT_PLAYER) {
+      if (arena[i][j] != OBJECT_TYPE_PLAYER) {
         temp_arena[i][j] = arena[i][j];
       } else {
-        temp_arena[i][j] = OBJECT_NONE;
+        temp_arena[i][j] = OBJECT_TYPE_NONE;
       }
     }
   }
@@ -1106,10 +1105,10 @@ random_teleport (void)
   iyp = yp = rand () % GAME_HEIGHT;
 
   while (1) {
-    if (temp_arena[xp][yp] == OBJECT_NONE) {
+    if (temp_arena[xp][yp] == OBJECT_TYPE_NONE) {
       player_xpos = xp;
       player_ypos = yp;
-      temp_arena[player_xpos][player_ypos] = OBJECT_PLAYER;
+      temp_arena[player_xpos][player_ypos] = OBJECT_TYPE_PLAYER;
 
       reset_player_animation ();
 
@@ -1166,10 +1165,10 @@ safe_teleport (void)
 
   for (i = 0; i < GAME_WIDTH; ++i) {
     for (j = 0; j < GAME_HEIGHT; ++j) {
-      if (arena[i][j] != OBJECT_PLAYER) {
+      if (arena[i][j] != OBJECT_TYPE_PLAYER) {
         temp_arena[i][j] = arena[i][j];
       } else {
-        temp_arena[i][j] = OBJECT_NONE;
+        temp_arena[i][j] = OBJECT_TYPE_NONE;
       }
     }
   }
@@ -1179,10 +1178,10 @@ safe_teleport (void)
 
   while (1) {
 
-    if ((temp_arena[xp][yp] == OBJECT_NONE) && check_safe (xp, yp)) {
+    if ((temp_arena[xp][yp] == OBJECT_TYPE_NONE) && check_safe (xp, yp)) {
       player_xpos = xp;
       player_ypos = yp;
-      temp_arena[player_xpos][player_ypos] = OBJECT_PLAYER;
+      temp_arena[player_xpos][player_ypos] = OBJECT_TYPE_PLAYER;
 
       reset_player_animation ();
 
diff --git a/src/gbdefs.h b/src/gbdefs.h
index 119df09..6d74f26 100644
--- a/src/gbdefs.h
+++ b/src/gbdefs.h
@@ -4,40 +4,12 @@
 #ifndef GBDEFS_H
 #define GBDEFS_H
 
-/*
- * Bubble Sizes
- */
-#define BUBBLE_WIDTH   86
-#define BUBBLE_HEIGHT  34
-#define BUBBLE_XOFFSET 8
-#define BUBBLE_YOFFSET 4
-
-/*
- * Size of the game playing area
- */
-#define GAME_WIDTH   45
-#define GAME_HEIGHT  30
-
 /*
  * Initial player position
  */
 #define PLAYER_DEF_XPOS (GAME_WIDTH/2)
 #define PLAYER_DEF_YPOS (GAME_HEIGHT/2)
 
-/*
- * Scenario pixmaps
- */
-#define SCENARIO_PIXMAP_WIDTH 14
-#define SCENARIO_PLAYER_START 0
-#define SCENARIO_ROBOT1_START 5
-#define SCENARIO_ROBOT2_START 9
-#define SCENARIO_HEAP_POS     13
-
-#define NUM_ROBOT_ANIMATIONS  4
-#define NUM_PLAYER_ANIMATIONS 4
-#define PLAYER_WAVE_WAIT      20
-#define PLAYER_NUM_WAVES      2
-
 /*
  * Animation
  */
@@ -52,24 +24,6 @@
 #define MAX_ROBOTS ((GAME_WIDTH*GAME_HEIGHT)/2)
 #define MAX_HEAPS  (MAX_ROBOTS/2)
 
-/*
- * Game object types
- */
-#define OBJECT_PLAYER 0
-#define OBJECT_HEAP   1
-#define OBJECT_ROBOT1 2
-#define OBJECT_ROBOT2 3
-#define OBJECT_NONE   99
-#define OBJECT_FOO    666
-
-/*
- * Bubble Types
- */
-#define BUBBLE_NONE  0
-#define BUBBLE_YAHOO 1
-#define BUBBLE_AIEEE 2
-#define BUBBLE_SPLAT 3
-
 /*
  * Game states
  */
diff --git a/src/gnome-robots.c b/src/gnome-robots.c
index ebe336b..b220ad3 100644
--- a/src/gnome-robots.c
+++ b/src/gnome-robots.c
@@ -35,7 +35,6 @@
 
 #include "gbdefs.h"
 #include "riiv.h"
-#include "graphics.h"
 #include "game.h"
 
 /* Minimum sizes. */
@@ -170,6 +169,22 @@ update_game_status (gint score, gint current_level, gint safes)
   g_free (button_text);
 }
 
+static gboolean
+draw_cb (GtkWidget * w, cairo_t * cr, gpointer data)
+{
+  gint i, j;
+
+  for (j = 0; j < GAME_HEIGHT; j++) {
+    for (i = 0; i < GAME_WIDTH; i++) {
+      draw_object (i, j, arena[i][j], cr);
+    }
+  }
+
+  draw_bubble (cr);
+
+  return TRUE;
+}
+
 const gchar *
 category_name_from_key (const gchar* key)
 {
@@ -473,7 +488,10 @@ activate (GtkApplication *app, gpointer user_data)
 
   load_properties ();
 
-  if (!load_game_graphics ()) {
+  GError *load_game_graphics_error = NULL;
+  load_game_graphics (&load_game_graphics_error);
+  if (load_game_graphics_error) {
+    g_error ("%s", load_game_graphics_error->message);
     /* Oops, no graphics, we probably haven't been installed properly. */
     errordialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window),
                                                       GTK_DIALOG_MODAL,
diff --git a/src/graphics.vala b/src/graphics.vala
new file mode 100644
index 0000000..8c2bacc
--- /dev/null
+++ b/src/graphics.vala
@@ -0,0 +1,459 @@
+/*
+ * Gnome Robots II
+ * written by Mark Rae <m rae inpharmatica co uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * For more details see the file COPYING.
+ */
+
+using Gtk;
+using Gdk;
+using Cairo;
+
+/*
+ * Size of the game playing area
+ */
+public const int GAME_WIDTH = 45;
+public const int GAME_HEIGHT = 30;
+
+public enum BubbleType {
+    NONE = 0,
+    YAHOO,
+    AIEEE,
+    SPLAT,
+}
+
+public const int BUBBLE_WIDTH = 86;
+public const int BUBBLE_HEIGHT = 34;
+public const int BUBBLE_XOFFSET = 8;
+public const int BUBBLE_YOFFSET = 4;
+
+/*
+ * Scenario pixmaps
+ */
+public const int SCENARIO_PIXMAP_WIDTH = 14;
+public const int SCENARIO_PLAYER_START = 0;
+public const int SCENARIO_ROBOT1_START = 5;
+public const int SCENARIO_ROBOT2_START = 9;
+public const int SCENARIO_HEAP_POS     = 13;
+
+public const int NUM_ROBOT_ANIMATIONS  = 4;
+public const int NUM_PLAYER_ANIMATIONS = 4;
+public const int PLAYER_WAVE_WAIT      = 20;
+public const int PLAYER_NUM_WAVES      = 2;
+
+public enum ObjectType {
+    PLAYER = 0,
+    HEAP = 1,
+    ROBOT1 = 2,
+    ROBOT2 = 3,
+    NONE = 99,
+    FOO = 666,
+}
+
+public int tile_width = 0;
+public int tile_height = 0;
+
+GamesPreimage theme_preimage = null;
+Pixbuf theme_pixbuf = null;
+bool rerender_needed = true;
+
+RGBA light_background;
+RGBA dark_background;
+
+Pixbuf aieee_pixbuf = null;
+Pixbuf yahoo_pixbuf = null;
+Pixbuf splat_pixbuf = null;
+
+int robot_animation = 0;
+int player_animation = 0;
+int player_num_waves = 0;
+int player_wave_wait = 0;
+int player_wave_dir = 1;
+
+int bubble_xpos = 0;
+int bubble_ypos = 0;
+int bubble_xo = 0;
+int bubble_yo = 0;
+BubbleType bubble_type = BubbleType.NONE;
+
+void render_graphics () {
+    theme_pixbuf = theme_preimage.render (14 * tile_width, tile_height);
+    rerender_needed = false;
+}
+
+public bool resize_cb (Widget w, EventConfigure e) {
+  int trial_width;
+  int trial_height;
+
+  trial_width = e.width / GAME_WIDTH;
+  trial_height = e.height / GAME_HEIGHT;
+
+  if ((trial_width != tile_width) || (trial_height != tile_height)) {
+    tile_width = trial_width;
+    tile_height = trial_height;
+    rerender_needed = true;
+  }
+
+  return false;
+}
+
+/**
+ * Loads all of the 'speech bubble' graphics
+ **/
+void load_bubble_graphics () throws Error {
+    yahoo_pixbuf = new Pixbuf.from_file (
+        GLib.Path.build_filename (DATA_DIRECTORY, "pixmaps", "yahoo.png"));
+    aieee_pixbuf = new Pixbuf.from_file (
+        GLib.Path.build_filename (DATA_DIRECTORY, "pixmaps", "aieee.png"));
+    splat_pixbuf = new Pixbuf.from_file (
+        GLib.Path.build_filename (DATA_DIRECTORY, "pixmaps", "splat.png"));
+}
+
+
+/**
+ * load_game_graphics
+ *
+ * Description:
+ * Loads all of the game graphics
+ *
+ * Returns:
+ * TRUE on success FALSE otherwise
+ **/
+public void load_game_graphics () throws Error {
+    if (theme_preimage != null) {
+        free_game_graphics ();
+    }
+
+    var themedir = GLib.Path.build_filename (DATA_DIRECTORY, "themes");
+    var filename = games_find_similar_file (properties_theme_name (), themedir);
+
+    try {
+        theme_preimage = new GamesPreimage.from_file (filename);
+    } catch (Error e) {
+        filename = games_find_similar_file ("robots", themedir);
+        theme_preimage = new GamesPreimage.from_file (filename);
+    }
+
+    load_bubble_graphics ();
+
+    rerender_needed = true;
+}
+
+/**
+ * Frees all of the resources used by the game graphics
+ **/
+public void free_game_graphics () {
+    theme_preimage = null;
+    theme_pixbuf = null;
+    aieee_pixbuf = null;
+    yahoo_pixbuf = null;
+    splat_pixbuf = null;
+}
+
+public void set_background_color (RGBA color) {
+    if (game_area == null)
+        return;
+
+    /* While the two colours are labelled "light" and "dark" which one is
+     * which actually depends on how light or dark the base colour is. */
+
+    double brightness = color.red + color.green + color.blue;
+    if (brightness > (1.0 / 1.1)) {
+        /* Darken light colours. */
+        light_background.red = 0.9 * color.red;
+        light_background.green = 0.9 * color.green;
+        light_background.blue = 0.9 * color.blue;
+    } else if (brightness > 0.04) {
+        /* Lighten darker colours. */
+        light_background.red = 1.1 * color.red;
+        light_background.green = 1.1 * color.green;
+        light_background.blue = 1.1 * color.blue;
+    } else {
+        /* Very dark colours, add rather than multiply. */
+        light_background.red += 0.04;
+        light_background.green += 0.04;
+        light_background.blue += 0.04;
+    }
+    light_background.alpha = 1.0;
+    dark_background = color;
+
+    clear_game_area ();
+}
+
+public void set_background_color_from_name (string name) {
+    RGBA color = RGBA ();
+    if (!color.parse (name)) {
+        color.parse ("#7590AE");
+    }
+    set_background_color (color);
+}
+
+/**
+ * draw_tile_pixmap
+ * @tileno: Graphics tile number
+ * @pno: Number of graphics set
+ * @x: x position in grid squares
+ * @y: y position in grid squares
+ * @cr: context to draw on
+ *
+ * Description:
+ * Draws tile pixmap @tileno from graphics set @pno at (@x, @y) in
+ * a widget @area
+ **/
+void draw_tile_pixmap (int tileno, int x, int y, Context cr) {
+    if ((x + y) % 2 != 0) {
+        cairo_set_source_rgba (cr, dark_background);
+    } else {
+        cairo_set_source_rgba (cr, light_background);
+    }
+
+    x *= tile_width;
+    y *= tile_height;
+
+    cr.rectangle (x, y, tile_width, tile_height);
+    cr.fill ();
+
+    if (rerender_needed)
+        render_graphics ();
+
+    if ((tileno < 0) || (tileno >= SCENARIO_PIXMAP_WIDTH)) {
+        /* nothing */
+    } else {
+        cairo_set_source_pixbuf (cr, theme_pixbuf, x - tileno * tile_width, y);
+        cr.rectangle (x, y, tile_width, tile_height);
+        cr.fill ();
+    }
+}
+
+
+/**
+ * draw_object
+ * @x: x position
+ * @y: y position
+ * @type: object type
+ * @cr: context to draw on
+ *
+ * Description:
+ * Draws graphics for an object at specified location
+ **/
+public void draw_object (int x, int y, ObjectType type, Context cr) {
+    if (game_area == null)
+        return;
+
+    switch (type) {
+    case ObjectType.PLAYER:
+        draw_tile_pixmap (SCENARIO_PLAYER_START + player_animation, x, y, cr);
+        break;
+    case ObjectType.ROBOT1:
+        draw_tile_pixmap (SCENARIO_ROBOT1_START + robot_animation, x, y, cr);
+        break;
+    case ObjectType.ROBOT2:
+        draw_tile_pixmap (SCENARIO_ROBOT2_START + robot_animation, x, y, cr);
+        break;
+    case ObjectType.HEAP:
+        draw_tile_pixmap (SCENARIO_HEAP_POS, x, y, cr);
+        break;
+    case ObjectType.NONE:
+        draw_tile_pixmap (-1, x, y, cr);
+        break;
+    }
+}
+
+
+/**
+ * clears the whole of the game area
+ **/
+public void clear_game_area () {
+    if (game_area == null)
+        return;
+
+    game_area.queue_draw ();
+}
+
+
+/**
+ * reset_player_animation
+ *
+ * Description:
+ * resets player animation to standing position
+ **/
+public void reset_player_animation () {
+    player_wave_wait = 0;
+    player_num_waves = 0;
+    player_wave_dir = 1;
+    player_animation = 0;
+}
+
+
+/**
+ * player_animation_dead
+ *
+ * Description:
+ * sets player animation to be dead
+ **/
+public void player_animation_dead () {
+    player_wave_wait = 0;
+    player_num_waves = 0;
+    player_wave_dir = 1;
+    player_animation = NUM_PLAYER_ANIMATIONS;
+}
+
+
+/**
+ * animate_game_graphics
+ *
+ * Description:
+ * updates animation for object graphics
+ **/
+public void animate_game_graphics () {
+  ++robot_animation;
+  if (robot_animation >= NUM_ROBOT_ANIMATIONS) {
+    robot_animation = 0;
+  }
+
+  if (player_animation == NUM_PLAYER_ANIMATIONS) {
+    /* do nothing */
+  } else if (player_wave_wait < PLAYER_WAVE_WAIT) {
+    ++player_wave_wait;
+    player_animation = 0;
+  } else {
+    player_animation += player_wave_dir;
+    if (player_animation >= NUM_PLAYER_ANIMATIONS) {
+      player_wave_dir = -1;
+      player_animation -= 2;
+    } else if (player_animation < 0) {
+      player_wave_dir = 1;
+      player_animation = 1;
+      ++player_num_waves;
+      if (player_num_waves >= PLAYER_NUM_WAVES) {
+        reset_player_animation ();
+      }
+    }
+  }
+}
+
+/**
+ * Draws a bubble if there is one
+ **/
+public void draw_bubble (Context cr) {
+    if (bubble_type == BubbleType.NONE)
+        return;
+
+    Pixbuf pmap;
+    if (bubble_type == BubbleType.YAHOO) {
+        pmap = yahoo_pixbuf;
+    } else if (bubble_type == BubbleType.AIEEE) {
+        pmap = aieee_pixbuf;
+    } else {
+        pmap = splat_pixbuf;
+    }
+
+    cairo_set_source_pixbuf (cr, pmap, bubble_xpos - bubble_xo, bubble_ypos - bubble_yo);
+    cr.rectangle (bubble_xpos, bubble_ypos, BUBBLE_WIDTH, BUBBLE_HEIGHT);
+    cr.fill ();
+}
+
+/**
+ * add_bubble
+ * @x: x position
+ * @y: y position
+ *
+ * Description:
+ * adds a bubble at @x,@y
+ **/
+void add_bubble (BubbleType type, int x, int y) {
+    bubble_type = type;
+    bubble_xpos = x * tile_width - BUBBLE_WIDTH + BUBBLE_XOFFSET;
+    bubble_ypos = y * tile_height - BUBBLE_HEIGHT + BUBBLE_YOFFSET;
+
+    bubble_xo = 0;
+    bubble_yo = 0;
+
+    if (bubble_ypos < 0) {
+        bubble_yo = BUBBLE_HEIGHT;
+        bubble_ypos += BUBBLE_HEIGHT;
+    }
+    if (bubble_xpos < 0) {
+        bubble_xo = BUBBLE_WIDTH;
+        bubble_xpos += BUBBLE_WIDTH;
+    }
+    game_area.queue_draw ();
+}
+
+/**
+ * remove_bubble
+ *
+ * Description:
+ * removes all types of bubble
+ **/
+public void remove_bubble () {
+    if (bubble_type == BubbleType.NONE)
+        return;
+
+    bubble_type = BubbleType.NONE;
+    game_area.queue_draw ();
+}
+
+/**
+ * removes a splat bubble if there is one
+ **/
+public void remove_splat_bubble () {
+    if (bubble_type != BubbleType.SPLAT)
+        return;
+
+    bubble_type = BubbleType.NONE;
+    game_area.queue_draw ();
+}
+
+
+/**
+ * add_yahoo_bubble
+ * @x: x position
+ * @y: y position
+ *
+ * Description:
+ * adds and "Yahoo" bubble at @x,@y
+ **/
+public void add_yahoo_bubble (int x, int y) {
+    add_bubble (BubbleType.YAHOO, x, y);
+}
+
+
+/**
+ * add_aieee_bubble
+ * @x: x position
+ * @y: y position
+ *
+ * Description:
+ * adds and "Aieee" bubble at @x,@y
+ **/
+public void add_aieee_bubble (int x, int y) {
+    add_bubble (BubbleType.AIEEE, x, y);
+}
+
+/**
+ * add_splat_bubble
+ * @x: x position
+ * @y: y position
+ *
+ * Description:
+ * adds a "Splat" speech bubble at @x,@y
+ **/
+public void add_splat_bubble (int x, int y) {
+    add_bubble (BubbleType.SPLAT, x, y);
+    bubble_ypos += BUBBLE_YOFFSET;
+}
+
diff --git a/src/keyboard.c b/src/keyboard.c
index 04aa968..6173ca1 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -26,6 +26,7 @@
 #include <gdk/gdkkeysyms.h>
 
 #include "keyboard.h"
+#include "riiv.h"
 #include "game.h"
 
 /**********************************************************************/
diff --git a/src/main.vapi b/src/main.vapi
index 785dcbd..2882a9f 100644
--- a/src/main.vapi
+++ b/src/main.vapi
@@ -1,14 +1,13 @@
 public void keyboard_set (uint keys[9]);
 
-public bool load_game_graphics ();
-public void clear_game_area ();
-public void set_background_color (Gdk.RGBA color);
-
 public void start_new_game ();
 
 [CCode (cheader_filename = "gnome-robots.h")]
 public Gtk.Window window;
 
+[CCode (cheader_filename = "gnome-robots.h")]
+public Gtk.Widget game_area;
+
 [CCode (cheader_filename = "gnome-robots.h")]
 public GLib.Settings settings;
 
diff --git a/src/meson.build b/src/meson.build
index d9a3f9d..4fd8e94 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -19,6 +19,7 @@ vala_sources = files(
     'sound.vala',
     'cursors.vala',
     'properties.vala',
+    'graphics.vala',
 )
 
 vala_lib = static_library('riiv',
@@ -43,7 +44,6 @@ riiv_dependency = declare_dependency(
 sources = files(
     'game.c',
     'gnome-robots.c',
-    'graphics.c',
     'keyboard.c',
 )
 resources = gnome.compile_resources(
diff --git a/src/properties.vala b/src/properties.vala
index 79004ac..b28e49d 100644
--- a/src/properties.vala
+++ b/src/properties.vala
@@ -91,7 +91,11 @@ void pmap_selection (ComboBox combo) {
 
         conf_set_theme (properties.themename);
 
-        load_game_graphics ();
+        try {
+            load_game_graphics ();
+        } catch (Error e) {
+            // TODO
+        }
         clear_game_area ();
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]