/* $Id: api.c,v 1.8 2000/05/29 03:01:50 jhall 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 /* GNU Guile high */ #include "api.h" /* GNU Robots API */ #include "hooks.h" /* GNU Robots UI hooks */ #include "main.h" /* for exit_nicely */ #include "sign.h" /* a hack for +/- sign */ /* Globals (from main.c) */ extern int **map; extern int nrows; extern int ncols; extern int robot_x; extern int robot_y; extern int robot_dir; extern long robot_score; extern long robot_energy; extern long robot_shields; /* Globals. (this file only) */ int cdirs[] = { 'N', 'E', 'S', 'W' }; char *things[] = { "space", "food", "prize", "wall", "baddie", "robot" }; int cthings[] = { SPACE, FOOD, PRIZE, WALL, BADDIE, ROBOT }; /* Functions */ SCM robot_turn (SCM s_n) { int n; int i; int incr; n = gh_scm2int (s_n); /* turn left or right? */ incr = sign (n); for (i = 0; i < abs (n); i++) { robot_dir += incr; if (robot_dir > 3) { robot_dir = 0; } else if (robot_dir < 0) { robot_dir = 3; } /* animate the robot */ hook_add_robot (robot_x, robot_y, cdirs[robot_dir]); robot_energy -= 2; if (robot_energy < 1) { exit_nicely (); } } /* for */ return (SCM_BOOL_T); } SCM robot_move (SCM s_n) { int x_to, y_to; int dx, dy; int i; int n; n = gh_scm2int (s_n); /* determine changes to x,y */ switch (robot_dir) { case 0: /* N */ dx = 0; dy = -1 * sign (n); break; case 1: /* E */ dx = sign (n); dy = 0; break; case 2: /* S */ dx = 0; dy = sign (n); break; case 3: /* W */ dx = -1 * sign (n); dy = 0; break; } /* Move the robot */ for (i = 0; i < abs (n); 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) { exit_nicely (); } switch (map[y_to][x_to]) { case SPACE: /* space */ /* move the robot there */ map[robot_y][robot_x] = SPACE; map[y_to][x_to] = ROBOT; hook_add_thing (robot_x, robot_y, SPACE); hook_add_robot (x_to, y_to, cdirs[robot_dir]); robot_x = x_to; robot_y = y_to; break; case BADDIE: /* baddie */ /* Damage */ robot_shields -= 10; if (robot_shields < 1) { exit_nicely (); } return (SCM_BOOL_F); break; case WALL: /* wall */ /* less damage */ robot_shields -= 2; if (robot_shields < 1) { exit_nicely (); } return (SCM_BOOL_F); break; default: /* even less damage */ if (--robot_shields < 1) { exit_nicely (); } return (SCM_BOOL_F); break; } } /* for */ return (SCM_BOOL_T); } SCM robot_smell (SCM s_th) { int th; int i, j; char *str; str = gh_scm2newstr (s_th, NULL); th = what_thing (str); free (str); /* no matter what, this took energy */ if (--robot_energy < 1) { exit_nicely (); } /* 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[j][i] == th) { /* Found it */ return (SCM_BOOL_T); } } /* for */ } /* for */ /* Failed to find it */ return (SCM_BOOL_F); } SCM robot_feel (SCM s_th) { int th; int x_to, y_to; int dx, dy; char *str; str = gh_scm2newstr (s_th, NULL); th = what_thing (str); free (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) { exit_nicely (); } /* Feel for the thing */ x_to = robot_x + dx; y_to = robot_y + dy; hook_robot_feel (robot_x, robot_y, cdirs[robot_dir], x_to, y_to); if (map[y_to][x_to] == BADDIE) { /* touching a baddie is hurtful */ if (robot_shields < 1) { exit_nicely (); } } if (map[y_to][x_to] == th) { return (SCM_BOOL_T); } /* Did not feel it */ return (SCM_BOOL_F); } SCM robot_look (SCM s_th) { int th; int x_to, y_to; int dx, dy; char *str; str = gh_scm2newstr (s_th, NULL); th = what_thing (str); free (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) { exit_nicely (); } /* Look for the thing */ x_to = robot_x + dx; y_to = robot_y + dy; while (map[y_to][x_to] == SPACE) { /* move the focus */ x_to += dx; y_to += dy; } /* Outside the loop, we have found something */ if (map[y_to][x_to] == th) { return (SCM_BOOL_T); } /* else, we did not find it */ return (SCM_BOOL_F); } SCM robot_grab (void) { int x_to, y_to; int dx, dy; /* 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; } /* Try to grab the thing */ x_to = robot_x + dx; y_to = robot_y + dy; robot_energy -= 5; if (robot_energy < 1) { exit_nicely (); } hook_robot_grab (robot_x, robot_y, cdirs[robot_dir], x_to, y_to); /* Did we grab it? */ switch (map[y_to][x_to]) { case SPACE: case WALL: case ROBOT: return (SCM_BOOL_F); break; case BADDIE: robot_shields -= 10; if (robot_shields < 1) { exit_nicely (); } return (SCM_BOOL_F); 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[y_to][x_to] = SPACE; hook_add_thing (x_to, y_to, SPACE); return (SCM_BOOL_T); } SCM robot_zap (void) { int x_to, y_to; int dx, dy; /* 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; } /* Try to zap the thing */ x_to = robot_x + dx; y_to = robot_y + dy; robot_energy -= 10; if (robot_energy < 1) { exit_nicely (); } hook_robot_zap (robot_x, robot_y, cdirs[robot_dir], x_to, y_to); /* Did we destroy it? */ switch (map[y_to][x_to]) { case SPACE: case WALL: case ROBOT: /* what to w/ robots? */ return (SCM_BOOL_F); break; case BADDIE: case FOOD: case PRIZE: hook_add_thing (x_to, y_to, SPACE); break; } /* only success gets here */ map[y_to][x_to] = SPACE; hook_add_thing (x_to, y_to, SPACE); return (SCM_BOOL_T); } SCM robot_stop (void) { /* Must be a SCM function, even though it returns no value */ /* Stop the robot immediately */ exit_nicely (); return (SCM_BOOL_T); /* never gets here */ } SCM robot_get_shields (void) { /* Returns the robot shields */ return (gh_long2scm (robot_shields)); } SCM robot_get_energy (void) { /* Returns the robot energy */ return (gh_long2scm (robot_energy)); } SCM robot_get_score (void) { /* Returns the robot score */ return (gh_long2scm (robot_score)); } int what_thing (const char *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 int he 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. */ int i; for (i = 0; i < 6; i++) { if (strcmp (th, things[i]) == 0) { return (cthings[i]); } } /* for */ /* not found */ return (-1); }