From e6e7222d5a730368ed4e84c2e0f55427460e5230 Mon Sep 17 00:00:00 2001 From: Bradley Smith Date: Mon, 21 Jan 2008 00:16:45 +0000 Subject: Imported GNU robots from CVS. Signed-off-by: Bradley Smith --- src/Makefile.am | 12 + src/api.c | 160 ++++++++++ src/grobot.c | 833 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 565 +++++++++++++++++++++++++++++++++++ src/map.c | 297 +++++++++++++++++++ src/sign.c | 16 + src/userinterface.c | 192 ++++++++++++ 7 files changed, 2075 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/api.c create mode 100644 src/grobot.c create mode 100644 src/main.c create mode 100644 src/map.c create mode 100644 src/sign.c create mode 100644 src/userinterface.c (limited to 'src') 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 +#include /* for abs, free */ + +#include +#include /* 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 +#include + +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 +#include /* for getopt */ +#include /* for strdup */ + +#include +#include + +#include + +#include /* for GNU getopt_long */ +#include /* 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 /* for getopt */ +#include +#include /* for strdup */ + +#include + +#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 +#include + +/* 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 + +#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); +} + -- cgit v1.1