summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am12
-rw-r--r--src/api.c160
-rw-r--r--src/grobot.c833
-rw-r--r--src/main.c565
-rw-r--r--src/map.c297
-rw-r--r--src/sign.c16
-rw-r--r--src/userinterface.c192
7 files changed, 2075 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..47d7f3b
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,12 @@
+bin_PROGRAMS = grobots
+
+INCLUDES = $(GLIB2_CFLAGS) $(GUILE_CFLAGS) -I$(top_builddir)/include \
+ -DPKGLIBDIR=\"$(pkglibdir)\" \
+ -DABS_TOP_BUILDDIR=\"$(abs_top_builddir)\" \
+ -DPKGDATADIR=\"$(pkgdatadir)\" \
+ -DMAPS_PATH=\"$(mapsdir)\" \
+ -DSCRIPTS_PATH=\"$(schemedir)\"
+
+grobots_SOURCES = main.c api.c sign.c map.c grobot.c userinterface.c
+grobots_LDFLAGS = $(GLIB2_LIBS) $(GUILE_LDFLAGS) -lltdl
+
diff --git a/src/api.c b/src/api.c
new file mode 100644
index 0000000..81776e5
--- /dev/null
+++ b/src/api.c
@@ -0,0 +1,160 @@
+/* $Id: api.c,v 1.16 2005/09/06 19:55:40 zeenix Exp $ */
+
+/* Robot API for the GNU Robots game */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for abs, free */
+
+#include <glib.h>
+#include <libguile.h> /* GNU Guile high */
+
+#include "api.h" /* GNU Robots API */
+#include "main.h" /* for exit_nicely */
+#include "sign.h" /* a hack for +/- sign */
+#include "grobot.h"
+
+extern GRobot *robot;
+
+/* Functions */
+
+SCM
+api_robot_turn (SCM s_n)
+{
+ g_robot_turn (robot, scm_num2int (s_n, 0, NULL));
+
+ return SCM_BOOL (TRUE);
+}
+
+SCM
+api_robot_move (SCM s_n)
+{
+ return SCM_BOOL (g_robot_move (robot, scm_num2int (s_n, 0, NULL)));
+}
+
+SCM
+api_robot_smell (SCM s_th)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = SCM_STRING_CHARS (s_th);
+ ret = g_robot_smell (robot, str);
+
+ return SCM_BOOL (ret);
+}
+
+SCM
+api_robot_feel (SCM s_th)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = SCM_STRING_CHARS (s_th);
+ ret = g_robot_feel (robot, str);
+
+ return SCM_BOOL (ret);
+}
+
+SCM
+api_robot_look (SCM s_th)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = SCM_STRING_CHARS (s_th);
+ ret = g_robot_look (robot, str);
+
+ return SCM_BOOL (ret);
+}
+
+SCM
+api_robot_grab (void)
+{
+ return SCM_BOOL (g_robot_grab (robot));
+}
+
+SCM
+api_robot_zap (void)
+{
+ return SCM_BOOL (g_robot_zap (robot));
+}
+
+SCM
+api_robot_stop (void)
+{
+ return SCM_BOOL (g_robot_stop (robot));
+}
+
+SCM
+api_robot_get_shields (void)
+{
+ glong shields;
+
+ g_object_get (robot, "shields", &shields, NULL);
+
+ /* Returns the robot shields */
+ return (scm_long2num (shields));
+}
+
+SCM
+api_robot_get_energy (void)
+{
+ glong energy;
+
+ g_object_get (robot, "energy", &energy, NULL);
+
+ /* Returns the robot energy */
+ return (scm_long2num (energy));
+}
+
+SCM
+api_robot_get_score (void)
+{
+ glong score;
+
+ g_object_get (robot, "score", &score, NULL);
+
+ /* Returns the robot score */
+ return (scm_long2num (score));
+}
+
+void
+api_init (void)
+{
+ /* define some new builtins (hooks) so that they are available in
+ Scheme. */
+
+ scm_c_define_gsubr ("robot-turn", 1, 0, 0, api_robot_turn);
+ scm_c_define_gsubr ("robot-move", 1, 0, 0, api_robot_move);
+ scm_c_define_gsubr ("robot-smell", 1, 0, 0, api_robot_smell);
+ scm_c_define_gsubr ("robot-feel", 1, 0, 0, api_robot_feel);
+ scm_c_define_gsubr ("robot-look", 1, 0, 0, api_robot_look);
+ scm_c_define_gsubr ("robot-grab", 0, 0, 0, api_robot_grab);
+ scm_c_define_gsubr ("robot-zap", 0, 0, 0, api_robot_zap);
+
+ scm_c_define_gsubr ("robot-get-shields", 0, 0, 0, api_robot_get_shields);
+ scm_c_define_gsubr ("robot-get-energy", 0, 0, 0, api_robot_get_energy);
+ scm_c_define_gsubr ("robot-get-score", 0, 0, 0, api_robot_get_score);
+
+ scm_c_define_gsubr ("stop", 0, 0, 0, api_robot_stop);
+ scm_c_define_gsubr ("quit", 0, 0, 0, api_robot_stop);
+}
+
diff --git a/src/grobot.c b/src/grobot.c
new file mode 100644
index 0000000..89602a0
--- /dev/null
+++ b/src/grobot.c
@@ -0,0 +1,833 @@
+/* Robot object for the GNU Robots game */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "grobot.h"
+#include "configs.h"
+#include "userinterface.h" /* GNU Robots UI */
+#include <stdio.h>
+#include <glib.h>
+
+enum
+{
+ DEATH,
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_POS_X,
+ ARG_POS_Y,
+ ARG_DIRECTION,
+ ARG_SCORE,
+ ARG_ENERGY,
+ ARG_SHIELDS,
+ ARG_UNITS,
+ ARG_SHOTS,
+
+ ARG_USER_INTERFACE,
+ ARG_MAP
+};
+
+static gchar *things[] = { "space", "food", "prize", "wall", "baddie", "robot" };
+static gint cthings[] = { SPACE, FOOD, PRIZE, WALL, BADDIE, ROBOT };
+
+GType _g_robot_type;
+
+static guint g_robot_signals[LAST_SIGNAL] = { 0 };
+static void g_robot_class_init (GRobotClass * klass);
+
+static void g_robot_dispose (GObject * object);
+static void g_robot_finalize (GObject * object);
+
+static void g_robot_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void g_robot_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GObjectClass *parent_class = NULL;
+
+static gint what_thing (const gchar *th);
+
+GType
+g_robot_get_type (void)
+{
+ if (!_g_robot_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GRobotClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) g_robot_class_init,
+ NULL,
+ NULL,
+ sizeof (GRobot),
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ };
+
+ _g_robot_type =
+ g_type_register_static (G_TYPE_OBJECT,
+ "GRobot",
+ &object_info,
+ 0);
+ }
+
+ return _g_robot_type;
+}
+
+static void
+g_robot_class_init (GRobotClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ gobject_class->dispose = g_robot_dispose;
+ gobject_class->finalize = g_robot_finalize;
+ gobject_class->set_property = g_robot_set_property;
+ gobject_class->get_property = g_robot_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POS_X,
+ g_param_spec_int ("x",
+ "x",
+ "X co-ordinate of current Position of the Robot",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POS_Y,
+ g_param_spec_int ("y",
+ "y",
+ "y co-ordinate of current Position of the Robot",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DIRECTION,
+ g_param_spec_int ("direction",
+ "direction",
+ "current Direction of the Robot",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCORE,
+ g_param_spec_long ("score",
+ "Score",
+ "current Score of the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ENERGY,
+ g_param_spec_long ("energy",
+ "Energy",
+ "current Energy-level of the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SHIELDS,
+ g_param_spec_long ("shields",
+ "Shields",
+ "current Shield-level of the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UNITS,
+ g_param_spec_long ("units",
+ "Units",
+ "Units walked by the Robot so far",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SHOTS,
+ g_param_spec_long ("shots",
+ "Shots",
+ "Number of Shots fired by the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_USER_INTERFACE,
+ g_param_spec_object ("user-interface",
+ "UserInterface",
+ "Reference to the UI object",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAP,
+ g_param_spec_object ("map",
+ "Map",
+ "Reference to the Game Map object",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_robot_signals[DEATH] =
+ g_signal_new ("death",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GRobotClass, death),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0, NULL);
+}
+
+static void
+g_robot_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GRobot *robot;
+ GObject *obj;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_ROBOT (object));
+
+ robot = G_ROBOT (object);
+
+ switch (prop_id) {
+ case ARG_POS_X:
+ robot->x = g_value_get_int (value);
+ break;
+ case ARG_POS_Y:
+ robot->y = g_value_get_int (value);
+ break;
+ case ARG_DIRECTION:
+ robot->dir = g_value_get_int (value);
+ break;
+ case ARG_SCORE:
+ robot->score = g_value_get_long (value);
+ break;
+ case ARG_ENERGY:
+ robot->energy = g_value_get_long (value);
+ break;
+ case ARG_SHIELDS:
+ robot->shields = g_value_get_long (value);
+ break;
+ case ARG_SHOTS:
+ robot->shots = g_value_get_long (value);
+ break;
+ case ARG_UNITS:
+ robot->units = g_value_get_long (value);
+ break;
+ case ARG_USER_INTERFACE:
+ if (robot->ui != NULL) {
+ g_object_unref (robot->ui);
+ }
+
+ obj = g_value_get_object (value);
+ if (obj != NULL) {
+ robot->ui = g_object_ref (obj);
+ }
+
+ else {
+ robot->ui = NULL;
+ }
+ break;
+ case ARG_MAP:
+ if (robot->map != NULL) {
+ g_object_unref (robot->map);
+ }
+
+ obj = g_value_get_object (value);
+ if (obj != NULL) {
+ robot->map = g_object_ref (obj);
+ }
+
+ else {
+ robot->map = NULL;
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_robot_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GRobot *robot;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_ROBOT (object));
+
+ robot = G_ROBOT (object);
+
+ switch (prop_id) {
+ case ARG_POS_X:
+ g_value_set_int (value, robot->x);
+ break;
+ case ARG_POS_Y:
+ g_value_set_int (value, robot->y);
+ break;
+ case ARG_DIRECTION:
+ g_value_set_int (value, robot->dir);
+ break;
+ case ARG_SCORE:
+ g_value_set_long (value, robot->score);
+ break;
+ case ARG_ENERGY:
+ g_value_set_long (value, robot->energy);
+ break;
+ case ARG_SHIELDS:
+ g_value_set_long (value, robot->shields);
+ break;
+ case ARG_SHOTS:
+ g_value_set_long (value, robot->shots);
+ break;
+ case ARG_UNITS:
+ g_value_set_long (value, robot->units);
+ break;
+ case ARG_USER_INTERFACE:
+ g_value_set_object (value, g_object_ref (G_OBJECT (robot->ui)));
+ break;
+ case ARG_MAP:
+ g_value_set_object (value, g_object_ref (G_OBJECT (robot->map)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+GRobot *
+g_robot_new (gint x, gint y, gint dir, glong score, glong energy, glong shields,
+ glong units, glong shots, UserInterface *ui, Map *map)
+{
+
+ return g_object_new (g_robot_get_type (),
+ "x", x,
+ "y", y,
+ "direction", dir,
+ "score", score,
+ "energy", energy,
+ "shields", shields,
+ "units", units,
+ "shots", shots,
+ "user_interface", ui,
+ "map", map,
+ NULL);
+}
+
+static void
+g_robot_dispose (GObject * object)
+{
+ GRobot *robot = G_ROBOT (object);
+
+ if (robot->ui != NULL) {
+ g_object_unref (G_OBJECT (robot->ui));
+ }
+
+ if (robot->map != NULL) {
+ g_object_unref (G_OBJECT (robot->map));
+ }
+
+ parent_class->dispose (object);
+}
+
+static void
+g_robot_finalize (GObject * object)
+{
+ parent_class->finalize (object);
+}
+
+void
+g_robot_turn (GRobot *robot, gint num_turns)
+{
+ gint i;
+ gint incr;
+
+ /* turn left or right? */
+
+ incr = sign (num_turns);
+
+ for (i = 0; i < abs (num_turns); i++) {
+ robot->dir += incr;
+
+ if (robot->dir > 3) {
+ robot->dir = 0;
+ }
+
+ else if (robot->dir < 0) {
+ robot->dir = 3;
+ }
+
+ /* animate the robot */
+ user_interface_move_robot (robot->ui, robot->x, robot->y, robot->x, robot->y, robot->dir, robot->energy, robot->score, robot->shields);
+
+ robot->energy -= 2;
+
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ } /* for */
+}
+
+gboolean
+g_robot_move (GRobot *robot, gint steps)
+{
+ gint x_to, y_to;
+ gint dx, dy;
+ gint i;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ /* determine changes to x,y */
+
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1 * sign (steps);
+ break;
+ case EAST: /* E */
+ dx = sign (steps);
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = sign (steps);
+ break;
+ case WEST: /* W */
+ dx = -1 * sign (steps);
+ dy = 0;
+ break;
+ }
+
+ /* Move the robot */
+
+ for (i = 0; i < abs (steps); i++) {
+ /* check for a space */
+
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ /* no matter what, this took energy */
+
+ robot->energy -= 2;
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ switch (MAP_GET_OBJECT (robot->map, x_to, y_to)) {
+ case SPACE: /* space */
+ /* move the robot there */
+
+ MAP_SET_OBJECT (robot->map, robot->x, robot->y, SPACE);
+ MAP_SET_OBJECT (robot->map, x_to, y_to, ROBOT);
+
+ user_interface_move_robot (robot->ui, robot->x, robot->y, x_to, y_to, robot->dir, robot->energy, robot->score, robot->shields);
+
+ robot->x = x_to;
+ robot->y = y_to;
+ robot->units++;
+
+ break;
+
+ case BADDIE: /* baddie */
+ /* Damage */
+
+ robot->shields -= 10;
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ return FALSE;
+
+ break;
+
+ case WALL: /* wall */
+ /* less damage */
+
+ robot->shields -= 2;
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ return (FALSE);
+
+ break;
+
+ default:
+ /* even less damage */
+
+ if (--robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ return (FALSE);
+
+ break;
+ }
+ } /* for */
+
+ return (TRUE);
+}
+
+gboolean
+g_robot_smell (GRobot *robot, gchar *str)
+{
+ gint th;
+ gint i, j;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ th = what_thing (str);
+
+ /* no matter what, this took energy */
+
+ if (--robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ user_interface_robot_smell (robot->ui, robot->x, robot->y, robot->dir, robot->energy, robot->score, robot->shields);
+
+ /* Smell for the thing */
+
+ for (i = robot->x - 1; i <= robot->x + 1; i++) {
+ for (j = robot->y - 1; j <= robot->y + 1; j++) {
+ if (!(i == robot->x && j == robot->y) && MAP_GET_OBJECT (robot->map, i, j) == th) {
+ /* Found it */
+
+ return (TRUE);
+ }
+ } /* for */
+ } /* for */
+
+ /* Failed to find it */
+
+ return (FALSE);
+}
+
+gboolean
+g_robot_feel (GRobot *robot, gchar *str)
+{
+ gint th;
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ th = what_thing (str);
+
+ /* determine changes to x,y */
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case EAST: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case WEST: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* no matter what, this took energy */
+ if (--robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ /* Feel for the thing */
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ user_interface_robot_feel (
+ robot->ui,
+ robot->x, robot->y,
+ robot->dir, x_to, y_to,
+ robot->energy, robot->score,
+ robot->shields);
+
+ if (MAP_GET_OBJECT (robot->map, x_to, y_to) == BADDIE) {
+ /* touching a baddie is hurtful */
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ }
+
+ if (MAP_GET_OBJECT (robot->map, x_to, y_to) == th) {
+ return (TRUE);
+ }
+
+ /* Did not feel it */
+ return (FALSE);
+}
+
+gboolean
+g_robot_look (GRobot *robot, gchar *str)
+{
+ gint th;
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ th = what_thing (str);
+
+ /* determine changes to x,y */
+ switch (robot->dir) {
+ case 0: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case 1: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case 2: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case 3: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* no matter what, this took energy */
+ if (--robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ /* Look for the thing */
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ user_interface_robot_look (
+ robot->ui,
+ robot->x, robot->y,
+ robot->dir, x_to, y_to,
+ robot->energy, robot->score,
+ robot->shields);
+
+ while (MAP_GET_OBJECT (robot->map, x_to, y_to) == SPACE) {
+ /* move the focus */
+ x_to += dx;
+ y_to += dy;
+ }
+
+ /* Outside the loop, we have found something */
+ if (MAP_GET_OBJECT (robot->map, x_to, y_to) == th) {
+ return (TRUE);
+ }
+
+ /* else, we did not find it */
+ return (FALSE);
+}
+
+gboolean
+g_robot_grab (GRobot *robot)
+{
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ /* determine changes to x,y */
+
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case EAST: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case WEST: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* Try to grab the thing */
+
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ robot->energy -= 5;
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ user_interface_robot_grab (robot->ui, robot->x, robot->y, robot->dir, x_to, y_to, robot->energy, robot->score, robot->shields);
+
+ /* Did we grab it? */
+
+ switch (MAP_GET_OBJECT (robot->map, x_to, y_to)) {
+ case SPACE:
+ case WALL:
+ case ROBOT:
+ return (FALSE);
+ break;
+
+ case BADDIE:
+ robot->shields -= 10;
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ return (FALSE);
+
+ case FOOD:
+ /* I want the net gain to be +10 */
+ robot->energy += 15;
+ break;
+
+ case PRIZE:
+ robot->score++;
+ break;
+ }
+
+ /* only successful grabs get here */
+ MAP_SET_OBJECT (robot->map, x_to, y_to, SPACE);
+ user_interface_add_thing (robot->ui, x_to, y_to, SPACE);
+
+ return (TRUE);
+}
+
+gboolean
+g_robot_zap (GRobot *robot)
+{
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ /* determine changes to x,y */
+
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case EAST: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case WEST: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* Try to zap the thing */
+
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ robot->energy -= 10;
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ robot->shots++;
+ user_interface_robot_zap (robot->ui, robot->x, robot->y, robot->dir, x_to, y_to, robot->energy, robot->score, robot->shields);
+
+ /* Did we destroy it? */
+ switch (MAP_GET_OBJECT (robot->map, x_to, y_to)) {
+ case SPACE:
+ case WALL:
+ case ROBOT: /* what to w/ robots? */
+ return (FALSE);
+ break;
+
+ case BADDIE:
+ case FOOD:
+ case PRIZE:
+ user_interface_add_thing (robot->ui, x_to, y_to, SPACE);
+ break;
+ }
+
+ /* only success gets here */
+ MAP_SET_OBJECT (robot->map, x_to, y_to, SPACE);
+ user_interface_add_thing (robot->ui, x_to, y_to, SPACE);
+
+ return (TRUE);
+}
+
+gboolean
+g_robot_stop (GRobot *robot)
+{
+ /* Must be a SCM function, even though it returns no value */
+ /* Stop the robot immediately */
+
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+
+ return (TRUE); /* never gets here */
+}
+
+static gint
+what_thing (const gchar *th)
+{
+ /* what_thing - this function scans the list of possible things
+ (strings) and returns a cthing. Returns -1 if not found in the
+ list. */
+
+ /* My idea here is that by return -1 on error, this won't match
+ anything in the list of cthings. That way, the function that
+ uses what_thing to determine the cthing doesn't have to care if
+ the call failed or not. This helps me keep the code simple,
+ since now I don't have to add a branch for failure, but which
+ also decrements energy. */
+
+ gint i;
+
+ for (i = 0; i < 6; i++) {
+ if (strcmp (th, things[i]) == 0) {
+ return (cthings[i]);
+ }
+ } /* for */
+
+ /* not found */
+
+ return (-1);
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ec6a581
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,565 @@
+/* $Id: main.c,v 1.28 2005/09/06 19:55:40 zeenix Exp $ */
+/*
+ GNU Robots game engine. This is the main() program, using GNU
+ Guile as my backend to handle the language.
+
+ Copyright (C) 1998 Jim Hall, jhall1@isd.net
+
+ GNU Robots 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 2 of the License, or
+ (at your option) any later version.
+
+ GNU Robots 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 GNU Robots; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <unistd.h> /* for getopt */
+#include <string.h> /* for strdup */
+
+#include <glib.h>
+#include <gmodule.h>
+
+#include <libguile.h>
+
+#include <getopt.h> /* for GNU getopt_long */
+#include <ltdl.h> /* For loading our ui plugins */
+
+#include "grobot.h" /* the robot structure, and robot manipulation routines */
+#include "api.h" /* robot API, as Scheme functions */
+#include "userinterface.h"
+#include "config.h"
+#include "configs.h"
+#include "map.h" /* Game Map */
+#include "main.h" /* for this source file */
+
+#define BUFF_LEN 1024
+#define MODULE_PREFIX "grobots-"
+#define MODULE_PATH_MAX 256
+#define MODULE_NAME_MAX 256
+
+/* Plugins we should know about STATICALLY */
+#define X11_MODULE "x11"
+#define CURSES_MODULE "curses"
+
+/* Globals (share with api.c) */
+GList *robots = NULL;
+GRobot *robot = NULL; // The current robot
+UserInterface *ui;
+Map *map;
+GModule *plugin;
+
+UserInterface * load_ui_module (gchar *module_name, Map *map);
+SCM catch_handler (void *data, SCM tag, SCM throw_args);
+
+/************************************************************************
+ * main() *
+ * The program starts here! *
+ ************************************************************************/
+
+gint
+main (gint argc, gchar *argv[])
+{
+ gint opt; /* the option read from getopt */
+
+ gint flag; /* flag passed back from getopt - NOT
+ USED */
+ gchar maps_path[MAX_PATH], scripts_path[MAX_PATH];
+
+ gchar *main_argv[5] = { "GNU Robots",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ struct option long_opts[] = {
+ {"version", 0, NULL, 'V'},
+ {"help", 0, NULL, 'h'},
+ {"map-file", 1, NULL, 'f'},
+ {"shields", 1, NULL, 's'},
+ {"energy", 1, NULL, 'e'},
+ {"plugin", 1, NULL, 'p'},
+ {NULL, 0, NULL, 0}
+ };
+
+ /* Initialize the GType system first */
+ g_type_init ();
+
+ /* Check command line */
+
+ /* Create a robot Object */
+ robot = g_robot_new (1, 1, 1, 0, DEFAULT_ENERGY, DEFAULT_SHIELDS, 0, 0, NULL, NULL);
+
+ g_assert (robot != NULL);
+
+ /* And add to to the list of robots */
+ robots = g_list_append (robots, robot);
+
+ while ((opt = getopt_long (argc, argv, "Vhf:s:e:p:", long_opts, &flag)) != EOF) {
+ switch (opt) {
+ case 'V':
+
+ /* Display version, then quit */
+ g_printf ("\n%s\n", PKGINFO);
+ g_printf ("%s\n", COPYRIGHT);
+ g_printf ("\nGNU Robots is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n");
+ g_printf ("\nGNU Robots is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n");
+ g_printf ("\nYou should have received a copy of the GNU General Public License\n"
+ "along with GNU Robots; if not, write to the Free Software\n"
+ "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n");
+ exit (0);
+ break;
+
+ case 'h':
+
+ /* Display help, then quit. */
+
+ usage (argv[0]);
+ exit (0);
+
+ break;
+
+ case 'f':
+
+ /* Set map file */
+
+ main_argv[1] = optarg; /* pointer assignment */
+
+ break;
+
+ case 's':
+
+ /* Set shields */
+
+ robot->shields = (glong) atol (optarg);
+
+ break;
+
+ case 'e':
+
+ /* Set energy */
+
+ robot->energy = (glong) atol (optarg);
+
+ break;
+
+ case 'p':
+
+ /* Set plugin */
+
+ main_argv[3] = optarg; /* pointer assignment */
+
+ break;
+
+ default:
+
+ /* invalid option */
+
+ usage (argv[0]);
+ exit (1);
+
+ break;
+ } /* switch */
+ } /* while */
+
+ /* Extra arg is the Scheme file */
+
+ if (optind < argc) {
+ /* Set Scheme file */
+
+ main_argv[2] = argv[optind]; /* pointer assignment */
+ }
+
+ /* Check that files have been given */
+ if (main_argv[1] == NULL) {
+ main_argv[1] = g_malloc (MAX_PATH);
+ g_strlcpy (main_argv[1], DEFAULT_MAP, MAX_PATH);
+ g_fprintf (stderr, "map file not specified, trying default: %s\n",
+ main_argv[1]);
+ }
+
+ /* Check that files exist */
+ g_strlcpy (maps_path, main_argv[1], MAX_PATH);
+
+ if (!is_file_readable (maps_path)) {
+ g_strlcpy (maps_path, MAPS_PATH, MAX_PATH);
+ g_strlcat (maps_path, "/", MAX_PATH);
+ g_strlcat (maps_path, main_argv[1], MAX_PATH);
+
+ if (!is_file_readable (maps_path)) {
+ gchar *env = getenv (MAPS_PATH_ENV);
+
+ if (env != NULL) {
+ g_strlcpy (maps_path, env, MAX_PATH);
+ g_strlcat (maps_path, "/", MAX_PATH);
+ g_strlcat (maps_path, main_argv[1], MAX_PATH);
+
+ if (!is_file_readable (maps_path)) {
+ g_fprintf (stderr,
+ "%s: %s: game map file does not exist or is not readable\n",
+ argv[0], main_argv[1]);
+ exit (1);
+ }
+ }
+
+ else {
+ g_fprintf (stderr,
+ "%s: %s: game map file does not exist or is not readable\n",
+ argv[0], main_argv[1]);
+ exit (1);
+ }
+ }
+ }
+
+ main_argv[1] = maps_path;
+
+ /* Now the Scheme file */
+ if (main_argv[2] != NULL) {
+ g_strlcpy (scripts_path, main_argv[2], MAX_PATH);
+
+ if (!is_file_readable (scripts_path)) {
+ g_strlcpy (scripts_path, SCRIPTS_PATH, MAX_PATH);
+ g_strlcat (scripts_path, "/", MAX_PATH);
+ g_strlcat (scripts_path, main_argv[2], MAX_PATH);
+
+ if (!is_file_readable (scripts_path)) {
+ gchar *env = getenv (SCRIPTS_PATH_ENV);
+
+ if (env != NULL) {
+ g_strlcpy (scripts_path, env, MAX_PATH);
+ g_strlcat (scripts_path, "/", MAX_PATH);
+ g_strlcat (scripts_path, main_argv[2], MAX_PATH);
+
+ if (!is_file_readable (scripts_path)) {
+ g_fprintf (stderr,
+ "%s: %s: Scheme file does not exist or is not readable\n",
+ argv[0], main_argv[2]);
+ exit (1);
+ }
+ }
+
+ else {
+ g_fprintf (stderr,
+ "%s: %s: Scheme file does not exist or is not readable\n",
+ argv[0], main_argv[2]);
+ exit (1);
+ }
+ }
+ }
+
+ main_argv[2] = scripts_path;
+ }
+
+ else {
+ /* argv[2] can't be NULL as argv[3] may also be NULL */
+ main_argv[2] = "";
+ }
+
+ /* Start Guile environment. Does not exit */
+ g_printf ("%s\n", PKGINFO);
+ g_printf ("%s\n", COPYRIGHT);
+ g_printf ("GNU Robots comes with ABSOLUTELY NO WARRANTY\n");
+ g_printf ("This is free software, and you are welcome to redistribute it\n");
+ g_printf ("under certain conditions; see the file `COPYING' for details.\n");
+ g_printf ("Loading Guile ... Please wait\n\n");
+
+ scm_boot_guile (3, main_argv, main_prog, NULL);
+
+ return 0; /* never gets here, but keeps compiler
+ happy */
+}
+
+/************************************************************************
+ * main_prog() *
+ * the main program code that is executed after Guile starts up. Pass *
+ * the Scheme program as argv[1] and the map file as argv[2]. The *
+ * program name is still argv[0]. *
+ ************************************************************************/
+
+void
+main_prog (void *closure, gint argc, gchar *argv[])
+{
+ gint i;
+ gchar *map_file = argv[1];
+ gchar *robot_program = argv[2];
+ gchar *module = argv[3];
+
+ api_init ();
+
+ g_printf ("Map file: %s\n", map_file);
+
+ map = map_new_from_file (map_file, DEFAULT_MAP_ROWS, DEFAULT_MAP_COLUMNS);
+
+ if (map == NULL) {
+ exit_nicely ();
+ }
+
+ /* ensure the robot is placed properly */
+ MAP_SET_OBJECT (map,
+ G_ROBOT_POSITION_Y (robot),
+ G_ROBOT_POSITION_X (robot),
+ ROBOT);
+
+ ui = load_ui_module (module, map);
+
+ if (ui == NULL) {
+ exit_nicely ();
+ }
+
+ /* Now initialize the rest of the Robot properties */
+ g_object_set (G_OBJECT (robot),
+ "user-interface", G_OBJECT (ui),
+ "map", G_OBJECT (map),
+ NULL);
+
+ g_signal_connect (G_OBJECT (robot), "death", G_CALLBACK (death), NULL);
+
+ /* draw the map */
+ user_interface_draw (ui);
+
+ if (strlen (robot_program) != 0) {
+ /* execute a Scheme file */
+ g_printf ("Robot program: %s\n", robot_program);
+ scm_c_primitive_load (robot_program);
+ }
+
+ else {
+ gchar buff[BUFF_LEN];
+ SCM value;
+
+ g_printf ("Robot program not specified. Entering interactive mode..\n");
+ while (1) {
+ user_interface_get_string (ui, "guile> ", buff, BUFF_LEN);
+ value = scm_internal_catch (SCM_BOOL_T,
+ (scm_t_catch_body) scm_c_eval_string,
+ (void *) buff,
+ catch_handler,
+ NULL);
+ }
+ }
+
+ /* done */
+ exit_nicely ();
+}
+
+/************************************************************************
+ * catch_handler (void *data, SCM tag, SCM throw_args);
+ *
+ * Responsible for handling errors
+ *************************************************************************/
+
+SCM catch_handler (void *data, SCM tag, SCM throw_args)
+{
+ gchar *message = "Could'nt get error message\n";
+
+ if(scm_ilength (throw_args) > 1 &&
+ SCM_NFALSEP (scm_string_p (SCM_CADR (throw_args)))) {
+ message = SCM_STRING_CHARS (SCM_CADR (throw_args));
+ }
+
+ else if (SCM_NFALSEP (scm_symbol_p (tag))) {
+ message = SCM_SYMBOL_CHARS (tag);
+ }
+
+ user_interface_update_status (ui, message, -1, -1, -1);
+
+ return SCM_BOOL_F;
+}
+
+void death (GRobot *robot)
+{
+ /* We get a ref increment on a signal */
+ g_object_unref (G_OBJECT (robot));
+
+ exit_nicely ();
+}
+
+UserInterface * load_ui_module (gchar *module_name, Map *map)
+{
+ UserInterface *ui = NULL;
+ UserInterfaceInitFunc user_interface_new = NULL;
+ gchar module_full_name[MODULE_NAME_MAX];
+ gchar module_path[MODULE_PATH_MAX];
+ gchar *module_full_path;
+ gint errors = 0;
+ const char *path = getenv (MODULE_PATH_ENV);
+
+ if (!g_module_supported ()) {
+ g_printf ("load_ui_module: %s\n", g_module_error ());
+ return;
+ }
+
+ if (path != NULL) {
+ g_strlcpy (module_path, path, MODULE_PATH_MAX);
+ }
+
+ else {
+ g_strlcpy (module_path, MODULE_PATH, MODULE_PATH_MAX);
+ }
+
+ /* Load the module. */
+ g_strlcpy (module_full_name, MODULE_PREFIX, MODULE_NAME_MAX);
+
+ if (module_name != NULL) {
+ g_strlcat (module_full_name, module_name, MODULE_NAME_MAX);
+ }
+
+ else {
+ if (getenv ("DISPLAY") != NULL) {
+ /* Yuppi! we have x */
+ g_strlcat (module_full_name, X11_MODULE, MODULE_NAME_MAX);
+ }
+
+ else {
+ g_strlcat (module_full_name, CURSES_MODULE, MODULE_NAME_MAX);
+ }
+ }
+
+ module_full_path = g_module_build_path (module_path, module_full_name);
+ plugin = g_module_open (module_full_path, 0);
+ g_free (module_full_path);
+
+ /* Find our handles. */
+ if (plugin) {
+ if (!(g_module_symbol (plugin, USER_INTERFACE_INIT_FUNCTION, (gpointer) &user_interface_new))) {
+ g_printf ("load_ui_module: %s\n", g_module_error ());
+ g_module_close (plugin);
+ plugin = NULL;
+ }
+
+ else {
+ ui = user_interface_new (map, user_interface_get_type ());
+ }
+ }
+
+ else {
+ g_printf ("error loading module '%s': %s\n", module_name, g_module_error ());
+ }
+
+ return ui;
+}
+
+/************************************************************************
+ * exit_nicely() *
+ * A function that allows the program to exit nicely, after freeing all *
+ * memory pointers, etc. *
+ ************************************************************************/
+void
+exit_nicely ()
+{
+ glong score, energy, shields, shots, units;
+
+ /* Stop the UI */
+ if (ui != NULL) {
+ g_object_unref (G_OBJECT (ui));
+ }
+
+ /* Get rid of the map object */
+ if (map != NULL) {
+ g_object_unref (G_OBJECT (map));
+ }
+
+ /* Show statistics */
+ g_object_get (G_OBJECT (robot),
+ "shields", &shields,
+ "energy", &energy,
+ "units", &units,
+ "shots", &shots,
+ "score", &score,
+ NULL);
+
+ g_list_foreach (robots, g_object_unref, NULL);
+ g_list_free (robots);
+
+ /* unload the plugin */
+ if (plugin != NULL) {
+ g_module_close (plugin);
+ }
+
+ g_printf ("\n-----------------------STATISTICS-----------------------\n");
+ g_printf ("Shields: %ld\n", (shields < 0 ? 0 : shields));
+ g_printf ("Energy: %ld\n", (energy < 0 ? 0 : energy));
+ g_printf ("Units walked: %ld\n", (units < 0 ? 0 : units));
+ g_printf ("Shots: %ld\n", (shots < 0 ? 0 : shots));
+ g_printf ("Score: %ld\n", score);
+
+ /* Show results, if any */
+ if (shields < 1) {
+ g_printf ("** Robot took too much damage, and died.\n");
+ }
+
+ else if (energy < 1) {
+ g_printf ("** Robot ran out of energy.\n");
+ }
+
+ /* Quit program */
+ exit (0);
+}
+
+/************************************************************************
+ * usage() *
+ * A function that prints the usage of GNU Robots to the user. Assume *
+ * text mode for this function. We have not initialized X Windows or *
+ * curses yet. *
+ ************************************************************************/
+
+void
+usage (const gchar *argv0)
+{
+ g_printf ("%s\n", PKGINFO);
+ g_printf ("%s\n", COPYRIGHT);
+ g_printf ("Game/diversion where you construct a program for a little robot\n");
+ g_printf ("then set him loose and watch him explore a world on his own.\n\n");
+
+ g_printf ("Usage: %s [OPTION]... [FILE]\n\n", argv0);
+ g_printf (" -f, --map-file=FILE Load map file (this option is required)\n");
+ g_printf (" -p, --plugin=PLUGIN Use plugin PLUGIN\n");
+ g_printf (" -s, --shields=N Set initial shields to N\n");
+ g_printf (" -e, --energy=N Set initial energy to N\n");
+ g_printf (" -V, --version Output version information and exit\n");
+ g_printf (" -h, --help Display this help and exit\n");
+ g_printf ("\nNote: FILE refers to a scheme file and %s enters into \n", argv0);
+ g_printf (" an interactive mode if it is not specified.\n");
+
+ g_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
+}
+
+/************************************************************************
+ * is_file_readable () *
+ * Checks if a file is a readable file. We will use this function as *
+ * part of a sanity check, before we get anywhere near having to open *
+ * files. This will save on error checking later on, when we may have *
+ * already initialized another environment (Curses, X Windows, ...) *
+ ************************************************************************/
+
+gint
+is_file_readable (const gchar *filename)
+{
+ FILE *stream;
+
+ stream = fopen (filename, "r");
+ if (stream == NULL) {
+ /* Failed */
+
+ return (0);
+ }
+
+ /* Success */
+
+ fclose (stream);
+ return (1);
+}
diff --git a/src/map.c b/src/map.c
new file mode 100644
index 0000000..bae21dc
--- /dev/null
+++ b/src/map.c
@@ -0,0 +1,297 @@
+/* GNU Robots. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <unistd.h> /* for getopt */
+#include <stdio.h>
+#include <string.h> /* for strdup */
+
+#include <glib.h>
+
+#include "configs.h"
+#include "map.h"
+
+enum
+{
+ ARG_0,
+ ARG_SIZE
+};
+
+GType _map_type = 0;
+
+static void map_class_init (MapClass * klass);
+static void map_init (GObject * object);
+
+static void map_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void map_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+map_get_type (void)
+{
+ if (!_map_type) {
+ static const GTypeInfo object_info = {
+ sizeof (MapClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) map_class_init,
+ NULL,
+ NULL,
+ sizeof (Map),
+ 0,
+ (GInstanceInitFunc) map_init,
+ NULL
+ };
+
+ _map_type =
+ g_type_register_static (G_TYPE_OBJECT,
+ "Map",
+ &object_info,
+ 0);
+ }
+
+ return _map_type;
+}
+
+static void
+map_class_init (MapClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ gobject_class->set_property = map_set_property;
+ gobject_class->get_property = map_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZE,
+ g_param_spec_pointer ("size",
+ "Size",
+ "The size of the map",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+}
+
+static void
+map_init (GObject * object)
+{
+ Map *map = MAP (object);
+
+ map->_map = NULL;
+ map->size.num_rows = -1;
+ map->size.num_cols = -1;
+}
+
+/* fload_map - loads a map file into memory. */
+static void
+fload_map (Map *map, FILE * stream)
+{
+ gint ch;
+ gint i, j;
+
+ /* Read the map file */
+ i = 0;
+ j = 0;
+
+ while ((ch = fgetc (stream)) != EOF) {
+ /* Add the ch to the map */
+
+ switch (ch) {
+ case SPACE:
+ case WALL:
+ case BADDIE:
+ case PRIZE:
+ case FOOD:
+ map->_map[j][i] = ch;
+ break;
+
+ case '\n':
+ /* ignore the newline */
+ break;
+
+ default:
+ /* not a valid map char, but we'll add a space anyway */
+
+ map->_map[j][i] = SPACE;
+ break;
+ } /* switch */
+
+ /* Check for newline */
+
+ if (ch == '\n') {
+ /* the line may have ended early. pad with WALL */
+
+ while (i < map->size.num_cols) {
+ map->_map[j][i++] = WALL;
+ }
+ }
+
+
+ /* if newline */
+ /* Check for limits on map */
+ if (++i >= map->size.num_cols) {
+ /* We have filled this line */
+
+ ++j;
+ i = 0;
+
+ /* Flush the buffer for this line */
+
+ while (ch != '\n') {
+ ch = fgetc (stream);
+ }
+ }
+ /* if i */
+ if (j >= map->size.num_rows) {
+ /* the map is filled */
+
+ return;
+ }
+ } /* while fgetc */
+
+ /* After the loop, we are done reading the map file. Make sure this
+ is bounded by WALL. */
+ if (i > 0) {
+ ++j;
+ }
+
+ for (i = 0; i < map->size.num_cols; i++) {
+ map->_map[j][i] = WALL;
+ }
+}
+
+static void
+cleanup_map (Map *map)
+{
+ gint i, j;
+
+ /* make sure there is a wall at top/bottom */
+
+ for (i = 0; i < map->size.num_cols; i++) {
+ map->_map[0][i] = WALL;
+ map->_map[map->size.num_rows - 1][i] = WALL;
+ }
+
+ /* make sure there is a wall at left/right */
+
+ for (j = 0; j < map->size.num_rows; j++) {
+ map->_map[j][0] = WALL;
+ map->_map[j][map->size.num_cols - 1] = WALL;
+ }
+}
+
+static void
+map_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ Map *map;
+ guint i;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_MAP (object));
+
+ map = MAP (object);
+
+ switch (prop_id) {
+ case ARG_SIZE:
+ /* Free the map if any */
+ if (map->_map != NULL) {
+ for (i = 0; i < map->size.num_rows; i++) {
+ g_free (map->_map[i]);
+ }
+
+ g_free (map->_map);
+ }
+
+ /* Get the new size of the map */
+ g_memmove (&map->size, g_value_get_pointer (value), sizeof (MapSize));
+
+ /* Allocate the according to the new size */
+ map->_map = g_malloc (map->size.num_rows * sizeof (gint **));
+
+ for (i = 0; i < map->size.num_rows; i++) {
+ map->_map[i] = g_malloc (map->size.num_cols * sizeof (gint));
+ }
+
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+map_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ Map *map;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_MAP (object));
+
+ map = MAP (object);
+
+ switch (prop_id) {
+ case ARG_SIZE:
+ g_value_set_pointer (value, g_memdup (&map->size, sizeof (MapSize)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+Map *
+map_new_from_file (const gchar *map_file, gint num_rows, gint num_cols)
+{
+ GObject *object;
+ Map *map;
+ gint **buf;
+ guint i;
+ FILE *stream;
+ MapSize size;
+
+ size.num_rows = num_rows;
+ size.num_cols = num_cols;
+
+ stream = fopen (map_file, "r");
+
+ if (stream != NULL) {
+ map = MAP (g_object_new (map_get_type (),
+ "size", &size,
+ NULL));
+ fload_map (map, stream);
+ fclose (stream);
+ cleanup_map (map);
+
+ return map;
+ }
+
+ /* else, no file to open */
+ else {
+ g_warning ("Could not open map file: %s\n", map_file);
+ return NULL;
+ }
+}
+
diff --git a/src/sign.c b/src/sign.c
new file mode 100644
index 0000000..07c9d7a
--- /dev/null
+++ b/src/sign.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <glib.h>
+
+/* is there a standard C function to do this? */
+
+gint
+sign (gint n)
+{
+ if (n < 0) {
+ return (-1);
+ } else if (n > 0) {
+ return (+1);
+ }
+
+ return (0);
+}
diff --git a/src/userinterface.c b/src/userinterface.c
new file mode 100644
index 0000000..c55f64f
--- /dev/null
+++ b/src/userinterface.c
@@ -0,0 +1,192 @@
+/* $Id: userinterface.c,v 1.7 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. This is the User Interface module */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib.h>
+
+#include "configs.h"
+#include "userinterface.h"
+
+/*enum
+{
+ ARG_0,
+ ARG_MAP
+};*/
+
+GType _user_interface_type = 0;
+
+static void user_interface_base_init (UserInterfaceClass * klass);
+
+GType
+user_interface_get_type (void)
+{
+ if (!_user_interface_type) {
+ static const GTypeInfo interface_info = {
+ sizeof (UserInterfaceClass),
+ (GBaseInitFunc) user_interface_base_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ NULL
+ };
+
+ _user_interface_type = g_type_register_static (G_TYPE_INTERFACE,
+ "UserInterface",
+ &interface_info,
+ 0);
+ }
+
+ return _user_interface_type;
+}
+
+static void
+user_interface_base_init (UserInterfaceClass * klass)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized) {
+ /*GObjectClass *gobject_class =
+ g_type_class_peek (((GTypeInterface *) klass)->g_instance_type);
+
+ g_object_class_install_property (gobject_class, ARG_MAP,*/
+ g_object_interface_install_property (
+ klass,
+ g_param_spec_object ("map",
+ "Map",
+ "Reference to the Game Map object",
+ G_TYPE_MAP,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ initialized = TRUE;
+ }
+}
+
+void user_interface_add_thing (UserInterface *ui,
+ gint x,
+ gint y,
+ gint thing)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_add_thing (ui, x, y, thing);
+}
+
+void user_interface_draw (UserInterface *ui)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_draw (ui);
+}
+
+void user_interface_move_robot (UserInterface *ui,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_move_robot (ui, from_x, from_y, to_x, to_y, cdir, energy, score, shields);
+}
+
+/* user_interfaces to animate the robot */
+ void user_interface_robot_smell (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_smell (ui, x, y, cdir, energy, score, shields);
+}
+
+void user_interface_robot_zap (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_zap (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+void user_interface_robot_feel (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_feel (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+void user_interface_robot_grab (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_grab (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+void user_interface_robot_look (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_look (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+/* user_interfaces to get/display data from/to user */
+void user_interface_get_string (UserInterface *ui,
+ gchar *prompt,
+ gchar *buff,
+ gint len)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_get_string (ui, prompt, buff, len);
+}
+
+void user_interface_update_status (UserInterface *ui,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_update_status (ui, s, energy, score, shields);
+}
+