[comp.sources.x] v04i017: xrobots, Part01/01

argv@island.uu.net (Dan Heller) (06/05/89)

Submitted-by: Brian Warkentine <bwarkent@polyslo.CalPoly.EDU>
Posting-number: Volume 4, Issue 17
Archive-name: xrobots/part01

[ This is an X version of the classic game of robots.  For those not familiar
  with robots, the idea is that you are chased by robots and the object is to
  make them crash into each other before they get you.  This is a very nice
  implementation of this game -- incredibly fun.  --argv ]

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Imakefile
#	Makefile.nonImake
#	README
#	bitmaps.h
#	callbacks.c
#	callbacks.h
#	game.c
#	game.h
#	graphics.c
#	graphics.h
#	help.c
#	help.h
#	main.c
#	score.c
#	score.h
#	xrobots.man
# This archive created: Tue May 30 14:19:53 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Imakefile'" '(642 characters)'
if test -f 'Imakefile'
then
	echo shar: will not over-write existing file "'Imakefile'"
else
cat << \SHAR_EOF > 'Imakefile'

     SCORE_FILE = -DSCORE_FILE=\"/usr/games/lib/xrobots_scores\"
      MAXSCORES = -DMAXSCORES=20
           MAXX = -DMAXX=35
           MAXY = -DMAXY=20
        DEFINES = $(SCORE_FILE) $(MAXSCORES) $(MAXX) $(MAXY)

           SRCS = callbacks.c game.c graphics.c main.c score.c help.c
           OBJS = callbacks.o game.o graphics.o main.o score.o help.o

       INCLUDES = -I$(TOP) -I$(TOOLKITSRC)
LOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB) -lm


all:: xrobots

ComplexProgramTarget(xrobots)
/*
 *  The following is a matter of preference:
 *
 *  InstallManPage(xrobots,$(MANDIR))
 *  InstallProgram(xrobots,$(BINDIR))
 */

SHAR_EOF
if test 642 -ne "`wc -c < 'Imakefile'`"
then
	echo shar: error transmitting "'Imakefile'" '(should have been 642 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile.nonImake'" '(1092 characters)'
if test -f 'Makefile.nonImake'
then
	echo shar: will not over-write existing file "'Makefile.nonImake'"
else
cat << \SHAR_EOF > 'Makefile.nonImake'

#  For those of us who are still confused by Imake,
#  this makefile is not its offspring.  :-)


        TASK		= xrobots
#       TASK		= /usr/games/xrobots

        SCORE_FILE	= -DSCORE_FILE=\"/usr/games/lib/xrobots_scores\"
        MAXSCORES	= -DMAXSCORES=20
        MAXX		= -DMAXX=35
        MAXY		= -DMAXY=20

        DEFINES		= $(SCORE_FILE) $(MAXSCORES) $(MAXX) $(MAXY)

        INCDIR		= /usr/local/include
        LIBDIR		= /usr/local/lib
        LIBS		= -lXaw -lXt -lXmu -lX11 -lm

        DBXFLAGS	= 
        CFLAGS		= $(DBXFLAGS) -I$(INCDIR) $(DEFINES)
        LDFLAGS		= $(DBXFLAGS) -L$(LIBDIR) $(LIBS)

        CFILES		= main.c game.c callbacks.c graphics.c score.c help.c
        OBJECTS		= main.o game.o callbacks.o graphics.o score.o help.o
        INCLUDES	= game.h graphics.h bitmaps.h score.h help.h

default: $(TASK) 
 
$(TASK): $(OBJECTS) $(INCLUDES) 
	cc -o $@ $(OBJECTS) $(LDFLAGS) 

.c.o:
	cc -c $*.c $(CFLAGS) 

tags: $(CFILES) $(INCLUDES)
	ctags -t $(INCLUDES) $(CFILES)

lint: 
	lint -I$(INCDIR) $(CFILES)

man::
	nroff -man xrobots.man

clean::
	rm -f $(OBJECTS)
SHAR_EOF
if test 1092 -ne "`wc -c < 'Makefile.nonImake'`"
then
	echo shar: error transmitting "'Makefile.nonImake'" '(should have been 1092 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(2510 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

README -- xrobots version 1.0 -- Thu May 25 13:23:49 PDT 1989

  xrobots is a game that runs on X Windows.  It is based on /usr/games/robots 
and on The New Daleks (Macintosh).  To create a runnable binary, type 
	make -f Makefile.nonImake
An Imakefile is also included.
  
Compile time parameters:  
 	  MAXX, MAXY -- these control the number of 'cells' in the playfield.
 	the default is 35x20.  The realistic maximum these can be on a 
 	1152x900 screen (ie most sun 3/50's) is about 50x40.  With a larger 
 	playfield, the scores will be higher and the game length longer, but
 	some graphics will appear slower.  I'd be interested to see this 
 	running on a bigger engine to see the effects.  With a 35x20 
 	playfield, scores in the 6000 range can be achieved.

 	  MAXSCORES -- the number of high scores that you want to keep.
 	The default is 20.

 	  The defaults for the binary is /usr/games/xrobots and the score
 	file is /usr/games/lib/xrobots_scores.  The binary should have
 	write access to the high score file (xrobots will attempt to 
 	create this itself).  

  There is a little bsd-ish stuff in score.c.  flock is used to stop a race 
condition.  If you don't have a bsd-like flock, you could probably 
comment it out.  The race condition (multiple users writing to the 
score file) is probably rare.

  xrobots has been tested on Sun 3/50's 3/60's 3/280's running the X11R3
server.  Also, it has been compiled and tested on a Pyramid running X11R2. 
(You'll have to comment out the references to XtNresize in score.c if you 
want it to compile under release 2.)

BUGS

  The man page doesn't install by default.  You'll have to do that yourself,
or if you are using imake, just remove the comments from the tail of the
Imakefile.

  None known.  There is a nasty bug in the awm window manager
that causes keypress events to be ignored.  It shows up now and then...
rather than code around it, I prefer another window manager.

-----

This insomnia killer was written by:
  Brian Warkentine (bwarkent@polyslo.CalPoly.EDU).

 Permission to use, copy, modify and distribute (without charge) this
   software, documentation, images, etc. is granted, provided that this 
   comment and the author's name is retained.  The author assumes no 
   responsibility for lost sleep as a consequence of use of this software.

 Send comments, bug reports, etc. to bwarkent@polyslo.CalPoly.EDU.
   (Soon to be at @Sun.COM, so if the previous address doesn't work,
   try brian@csufres.CSUFresno.EDU.)

SHAR_EOF
if test 2510 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 2510 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'bitmaps.h'" '(6146 characters)'
if test -f 'bitmaps.h'
then
	echo shar: will not over-write existing file "'bitmaps.h'"
else
cat << \SHAR_EOF > 'bitmaps.h'
/*
 * bitmaps.h  --  xrobots v1.0
 */

/*----------------------------------------------------------------------*/
/* playfield images */

#define Image_player_width 20
#define Image_player_height 20
static char Image_player_bits[] = {
   0xc0, 0x1f, 0x00, 0x30, 0x60, 0x00, 0x08, 0x80, 0x00, 0x04, 0x00, 0x01,
   0x42, 0x10, 0x02, 0xe2, 0x38, 0x02, 0x41, 0x10, 0x04, 0x01, 0x00, 0x04,
   0x01, 0x00, 0x04, 0x11, 0x40, 0x04, 0x19, 0xc0, 0x04, 0x1d, 0xc0, 0x05,
   0x31, 0x60, 0x04, 0xe2, 0x38, 0x02, 0xc2, 0x1f, 0x02, 0x84, 0x0f, 0x01,
   0x08, 0x80, 0x00, 0x30, 0x60, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00};

#define Image_player_dead_width 20
#define Image_player_dead_height 20
static char Image_player_dead_bits[] = {
   0xc0, 0x1f, 0x00, 0x30, 0x60, 0x00, 0x08, 0x80, 0x00, 0x04, 0x00, 0x01,
   0x12, 0x45, 0x02, 0xa2, 0x28, 0x02, 0x41, 0x10, 0x04, 0xa1, 0x28, 0x04,
   0x11, 0x45, 0x04, 0x01, 0x00, 0x04, 0x01, 0x00, 0x04, 0x01, 0x00, 0x04,
   0x01, 0x00, 0x04, 0x02, 0x00, 0x02, 0xf2, 0x7f, 0x02, 0x04, 0x00, 0x01,
   0x08, 0x80, 0x00, 0x30, 0x60, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00};

#define Image_robot_width 20
#define Image_robot_height 20
static char Image_robot_bits[] = {
   0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x10, 0x40, 0x00, 0xe8, 0xff, 0x00,
   0x04, 0x38, 0x01, 0xfa, 0xff, 0x03, 0x42, 0x15, 0x02, 0xaa, 0xaa, 0x02,
   0x4a, 0x95, 0x02, 0x8a, 0x8a, 0x02, 0x1a, 0xc5, 0x02, 0x2a, 0xa2, 0x02,
   0x2a, 0xa0, 0x02, 0x2e, 0xa2, 0x03, 0x20, 0x22, 0x00, 0x20, 0x22, 0x00,
   0x20, 0x22, 0x00, 0x20, 0x22, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00};

#ifdef HEAP_STYLE_1
/* your choice of how you like your dead robots to look...*/

#define Image_heap_width 20
#define Image_heap_height 20
static char Image_heap_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xe0, 0xff, 0x01, 0x20, 0x00, 0x03, 0xa0, 0xaa, 0x06, 0xff, 0x57, 0x0d,
   0x01, 0xe8, 0x0a, 0x55, 0xf5, 0x0a, 0xa9, 0xfa, 0x0e, 0x55, 0xfd, 0x0a,
   0xbf, 0xfe, 0x0e, 0x55, 0xfd, 0x0a, 0xab, 0x7a, 0x0e, 0x55, 0x75, 0x0a,
   0xff, 0xea, 0x06, 0xe0, 0x5f, 0x03, 0xa0, 0xaa, 0x01, 0xe0, 0xff, 0x00};

#else

#define Image_heap_width 20
#define Image_heap_height 20
static char Image_heap_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x1e, 0x00,
   0x00, 0x35, 0x00, 0x80, 0x5b, 0x00, 0xc0, 0xae, 0x00, 0xe0, 0xf5, 0x00,
   0xb0, 0xaa, 0x01, 0xe8, 0x6f, 0x03, 0x7c, 0xfe, 0x03, 0x00, 0x00, 0x00};

#endif


#define dot_width 16
#define dot_height 16
static char dot_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x06, 0x00, 0x09, 0x80, 0x10, 0x40, 0x20, 0x40, 0x20, 0x80, 0x10,
   0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00};

/*----------------------------------------------------------------------*/
/* cursors */

#define down_width 16
#define down_height 16
static char down_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01,
   0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xb0, 0x0d,
   0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00};

#define down_left_width 16
#define down_left_height 16
static char down_left_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x01, 0x80, 0x03, 0xc0, 0x01, 0xe6, 0x00, 0x76, 0x00, 0x3e, 0x00,
   0x1e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00};

#define down_right_width 16
#define down_right_height 16
static char down_right_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x80, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x7c,
   0x00, 0x78, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00};

#define left_width 16
#define left_height 16
static char left_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x18, 0x00,
   0x0c, 0x00, 0xfe, 0x07, 0xfe, 0x07, 0x0c, 0x00, 0x18, 0x00, 0x10, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

#define right_width 16
#define right_height 16
static char right_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18,
   0x00, 0x30, 0xe0, 0x7f, 0xe0, 0x7f, 0x00, 0x30, 0x00, 0x18, 0x00, 0x08,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

#define up_width 16
#define up_height 16
static char up_bits[] = {
   0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xb0, 0x0d, 0x80, 0x01,
   0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

#define up_right_width 16
#define up_right_height 16
static char up_right_bits[] = {
   0x00, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x6e,
   0x00, 0x67, 0x80, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


#define up_left_width 16
#define up_left_height 16
static char up_left_bits[] = {
   0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1e, 0x00, 0x3e, 0x00, 0x76, 0x00,
   0xe6, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


#define stay_width 16
#define stay_height 16
static char stay_bits[] = {
   0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x10,
   0x08, 0x18, 0x18, 0xfc, 0x3f, 0x18, 0x18, 0x10, 0x08, 0x01, 0x80, 0x03,
   0xc0, 0x07, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01};


#define cant_go_width 16
#define cant_go_height 16
static char cant_go_bits[] = {
   0x00, 0x00, 0xc0, 0x07, 0x20, 0x08, 0x90, 0x13, 0x50, 0x12, 0x20, 0x12,
   0x00, 0x09, 0x80, 0x04, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, 0x00, 0x01,
   0x80, 0x02, 0x80, 0x02, 0x00, 0x01, 0x00, 0x00};


#define thumbs_down_width 16
#define thumbs_down_height 16
#define thumbs_down_x_hot 7
#define thumbs_down_y_hot 15
static char thumbs_down_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x1e, 0x40, 0x00, 0x78, 0x00, 0x80,
   0x00, 0x78, 0x00, 0x80, 0x00, 0x7c, 0x0e, 0x40, 0x30, 0x3e, 0x40, 0x03,
   0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0xc0, 0x00};
SHAR_EOF
if test 6146 -ne "`wc -c < 'bitmaps.h'`"
then
	echo shar: error transmitting "'bitmaps.h'" '(should have been 6146 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'callbacks.c'" '(7742 characters)'
if test -f 'callbacks.c'
then
	echo shar: will not over-write existing file "'callbacks.c'"
else
cat << \SHAR_EOF > 'callbacks.c'
/*
 * callbacks.c  --  xrobots v1.0
 */

#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <math.h>
#include "game.h"
#include "callbacks.h"
#include "graphics.h"

extern Widget sonic_command;

/*----------------------------------------------------------------------*/
/* Editorial note:  For most of the functions in this file, callbacks 
 * 	are nothing more than overgrown actions.  Both are used and
 *	needed.  Unfortunately, there's alot of boilerplate overhead.
 * 	Actually, all this could be done without any callbacks.
 */

/*ARGSUSED*/
XtCallbackProc
teleport_callback(widget,closure,callData)
  Widget widget;
  caddr_t closure;
  caddr_t callData;
{
  teleport();
}

/*ARGSUSED*/
static XtActionProc
teleport_action(w,event,params,num_params)
  Widget w;
  XEvent *event;
  String *params;
  Cardinal *num_params;
{
  teleport();
}


/*ARGSUSED*/
XtCallbackProc
wait_callback(widget,closure,callData)
  Widget widget;
  caddr_t closure;
  caddr_t callData;
{
  wait_for_em();
}


/*ARGSUSED*/
static XtActionProc
wait_action(w,event,params,num_params)
  Widget w;
  XEvent *event;
  String *params;
  Cardinal *num_params;
{
  wait_for_em();
}



/*ARGSUSED*/
XtCallbackProc
sonic_callback(widget,closure,callData)
  Widget widget;
  caddr_t closure;
  caddr_t callData;
{
  static Arg arg = { XtNsensitive, False};
  if(!game_active) return;
  XtSetValues(sonic_command,&arg,1);
  sonic_screwdriver();
}

/*ARGSUSED*/
static XtActionProc
sonic_action(w,event,params,num_params)
  Widget w;
  XEvent *event;
  String *params;
  Cardinal *num_params;
{
  static Arg arg = { XtNsensitive, False};
  if(!game_active) return;
  XtSetValues(sonic_command,&arg,1);
  sonic_screwdriver();
}


void
reset_sonic_button()
{
  static Arg arg = { XtNsensitive, True };
  XtSetValues(sonic_command,&arg,1);
}


/*ARGSUSED*/
XtCallbackProc
new_game_callback(widget,closure,callData)
  Widget widget;
  caddr_t closure;
  caddr_t callData;
{
  new_game();
}


/*ARGSUSED*/
static XtActionProc
new_game_action(w,event,params,num_params)
  Widget w;
  XEvent *event;
  String *params;
  Cardinal *num_params;
{
  new_game();
}


/*ARGSUSED*/
XtCallbackProc
quit_callback(widget,closure,callData)
  Widget widget;
  caddr_t closure;
  caddr_t callData;
{
 quit_game();
}

/*ARGSUSED*/
static XtActionProc
quit_action(w,event,params,num_params)
  Widget w;
  XEvent *event;
  String *params;
  Cardinal *num_params;
{
  quit_game();
}


/*ARGSUSED*/
static XtActionProc
do_nothing_action(w,event,params,num_params)
  Widget w;
  XEvent *event;
  String *params;
  Cardinal *num_params;
{
  /* do nothing */
}



/*----------------------------------------------------------------------*/


int 
determine_direction(button_x,button_y)
  int button_x,button_y;
{
/* 
 * Given the mouse's x&y position, this routine determines the direction
 * relative to the player, and returns the result coded into a int.
 */
  float slope, invslope;
  int direction = 0;
  int coord_x = pos_to_coord(human_x) + CELLSIZE/2,
      coord_y = pos_to_coord(human_y) + CELLSIZE/2;

  if( (abs(coord_x - button_x) < (CELLSIZE/2)+2) &&
      (abs(coord_y - button_y) < (CELLSIZE/2)+2)) 
    return(STILL);      /* cursor is directly over the player */ 

  if(button_x - coord_x != 0) {
    slope = fabs((float)(button_y - coord_y) / (float)(button_x - coord_x)); 

    if( button_x > coord_x ) {			/* in coordinates 1 or 4 */
      if( (slope < 2) && (human_x < MAXX) )
        direction = RIGHT;
    }
    else 					/* in coordinates 2 or 3 */
      if( (slope < 2) && (human_x > -1) )
        direction = LEFT;
  }

  if(button_y - coord_y != 0) {
    invslope = fabs((float)(button_x - coord_x) / (float)(button_y - coord_y)); 

    if( button_y > coord_y ) {			/* in coordinates 1 or 2 */
      if( (invslope < 2) && (human_y < MAXY) )
        direction |= DOWN;
    }

    else 					/* in coordinates 3 or 4 */
      if( (invslope < 2) && (human_y > -1) )
        direction |= UP;
  }
  return(direction);
}



/*----------------------------------------------------------------------*/


/*ARGSUSED*/
static XtActionProc
move_action(w,event,params,num_params)
  Widget w;
  XButtonEvent *event;
  String *params;
  Cardinal *num_params;
{
/* 
 *  Called to move the player's icon.  This action can be called 
 *  when a mouse button is pressed or when a key is pressed.
 *  This is all dependent on the current translations.
 */
  int direction;
  int tmp_human_x = human_x, tmp_human_y = human_y;
  int num_wasted;
  int param_count = *num_params;

  if(!game_active) return;

  if(!*num_params) {	/* no parameters - use the mouse pointer */

    direction = determine_direction(event->x,event->y);
    if(!direction)  return;

    if(direction & UP)    tmp_human_y--;
    if(direction & DOWN)  tmp_human_y++;
    if(direction & LEFT)  tmp_human_x--;
    if(direction & RIGHT) tmp_human_x++;

  } else 

    while(param_count--) {
      /* else pull the direction out of the parameters. */
      /* you can 'cheat' here... but who's gonna tell? */
      if(!strcmp("right",*(params+param_count)))
        tmp_human_x++;
      if(!strcmp("left", *(params+param_count)))
        tmp_human_x--;
      if(!strcmp("up",   *(params+param_count)))
        tmp_human_y--;
      if(!strcmp("down", *(params+param_count)))
        tmp_human_y++;
    }

  last_human_x = human_x;
  last_human_y = human_y;

  if( can_go(tmp_human_x,tmp_human_y) ) {
    human_x = tmp_human_x;
    human_y = tmp_human_y;
    num_wasted = chase();
    show_movement();
    add_score(num_wasted);
    if(!num_robots)
      new_level();
    else
      display_possible_moves();
    pointer_moved((Widget)0,(caddr_t)0,event);
  }

}




/*ARGSUSED*/
static XtActionProc
go_here_action(w,event,params,num_params)
  Widget w;
  XButtonEvent *event;
  String *params;
  Cardinal *num_params;
{
/* 
 * This action causes player's icon to try to go to a spot in the 
 * play area.  It stops if a move cannot be made.
 */
  int direction;
  int tmp_human_x, tmp_human_y;
  int num_wasted;

  if(!game_active) return;

  while(direction = determine_direction(event->x,event->y)) {
    if(direction == STILL) break;
    tmp_human_x = human_x;
    tmp_human_y = human_y;

    if(direction & UP)    tmp_human_y--;
    if(direction & DOWN)  tmp_human_y++;
    if(direction & LEFT)  tmp_human_x--;
    if(direction & RIGHT) tmp_human_x++;

    if( !can_go(tmp_human_x,tmp_human_y) ) 
      break;
    last_human_x = human_x;
    last_human_y = human_y;
    human_x = tmp_human_x;
    human_y = tmp_human_y;
    num_wasted = chase();
    show_movement();
    add_score(num_wasted);
    if(!num_robots) {
      new_level();
      break;
    }
    if(spiffy) {
      display_possible_moves();
      pointer_moved((Widget)0,(caddr_t)0,event);
    }
  }
  if(spiffy)
    display_possible_moves();
  pointer_moved((Widget)0,(caddr_t)0,event);
}



/*ARGSUSED*/
XtEventHandler
pointer_moved(w, closure, event)
  Widget w;
  caddr_t closure;
  XPointerMovedEvent *event;
{
  if(game_active) 
    update_pointer( determine_direction(event->x,event->y) );
}

/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/

static XtActionsRec actions[] = {
  {"wait",      (XtActionProc)wait_action},
  {"teleport",  (XtActionProc)teleport_action},
  {"sonic",     (XtActionProc)sonic_action},
  {"move",      (XtActionProc)move_action},
  {"go_here",   (XtActionProc)go_here_action},
  {"quit",      (XtActionProc)quit_action},
  {"new_game",  (XtActionProc)new_game_action},
  {"do_nothing",(XtActionProc)do_nothing_action},
};

void
init_actions()
{
   XtAddActions(actions,XtNumber(actions));
}


SHAR_EOF
if test 7742 -ne "`wc -c < 'callbacks.c'`"
then
	echo shar: error transmitting "'callbacks.c'" '(should have been 7742 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'callbacks.h'" '(309 characters)'
if test -f 'callbacks.h'
then
	echo shar: will not over-write existing file "'callbacks.h'"
else
cat << \SHAR_EOF > 'callbacks.h'
/*
 * callbacks.h  --  xrobots v1.0
 */

extern XtCallbackProc	teleport_callback(), 
			wait_callback(), 
			sonic_callback(), 
			quit_callback(), 
			new_game_callback();

extern XtEventHandler 	pointer_moved();

extern void 		reset_sonic_button(),
			init_actions();

extern int  		determine_direction();

SHAR_EOF
if test 309 -ne "`wc -c < 'callbacks.h'`"
then
	echo shar: error transmitting "'callbacks.h'" '(should have been 309 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'game.c'" '(6373 characters)'
if test -f 'game.c'
then
	echo shar: will not over-write existing file "'game.c'"
else
cat << \SHAR_EOF > 'game.c'
/*
 * game.c  --  xrobots v1.0
 *
 * Most of the game logic is here.  
 */

#include "game.h"
#include "score.h"

/* some of these are global */
int human_x, human_y, last_human_x, last_human_y;

int robot_array[MAXX][MAXY],
    robot_array_bak[MAXX][MAXY];	
	/* These arrays are filled with the robots and the heaps 
	 * They do not include the player(human).
	 */
int score;
int num_robots;
int level;
int game_active;
int sonic_used;

/*----------------------------------------------------------------------*/
void
new_game()
{
  score = 0;
  level = 0;
  sonic_used = 1;
  game_active = 1;
  new_level();
  update_score(score);
}

/*----------------------------------------------------------------------*/
void
add_score(n)
  int n;
{
  score += 10 * n; /* ten points for each wasted robot. */
  num_robots -= n;
  if(n) update_score(score);
}

/*----------------------------------------------------------------------*/
void
new_level()
{
  int x,y,tmp;

  reset_sonic_button();
  if(!sonic_used) {
    score += 50; 	/* bonus for not using sonic screwdriver on last level*/
    update_score(score);
  }
  sonic_used = 0;
  level++;
  num_robots = tmp = level*5;

  for_each                            /* clean out both the robot arrays */
  {
    robot_array[x][y] = EMPTY;
    robot_array_bak[x][y] = EMPTY;
  }
  
  human_x = (int)random()%MAXX;                  /* assign human to new space */
  human_y = (int)random()%MAXY;
  robot_array[human_x][human_y] = ROBOT;

  while(tmp--)
  {
    x = (int)random()%MAXX;
    y = (int)random()%MAXY;
    if(robot_array[x][y] == ROBOT) tmp++;        /* space already occupied */
    robot_array[x][y] = ROBOT;
  }
  robot_array[human_x][human_y] = EMPTY;
  display_level();
  display_possible_moves();
}

/*----------------------------------------------------------------------*/
int
chase()
{
  /* chase() returns the number of robots that were wasted in each call. */
  /* after each call, be sure to check if all the robots are dead */
  int x,y;
  int newx,newy;
  int num_wasted = 0;

  for_each
  {
    robot_array_bak[x][y] = robot_array[x][y];
    if(robot_array[x][y] != HEAP)
      robot_array[x][y] = 0;
  }

  for_each
  {
    if(robot_array_bak[x][y] != ROBOT)
      continue;

    if(x>human_x)                           /* move toward the human */
      newx = x-1;
    else  
      if(x<human_x)
        newx = x+1;
      else
        newx = x;

    if(y>human_y) 
      newy = y-1;
    else  
      if(y<human_y)
        newy = y+1;
      else
        newy = y;

#   ifdef DEBUG
    printf("moving (%d,%d) to (%d,%d)\n",x,y,newx,newy);
#   endif

    /* check to see if a robot or heap was already in that spot */
    if(robot_array[newx][newy] == ROBOT)
    {
      robot_array[newx][newy] = HEAP;
      num_wasted += 2;
      continue;
    }
    if(robot_array[newx][newy] == HEAP)
    {
      num_wasted++;
      continue;
    }
    /* move robot to new location */
    robot_array[newx][newy] = ROBOT;
  }
  return(num_wasted);
}

/*----------------------------------------------------------------------*/
void
undo_chase()
{
  int x,y;
  for_each
    robot_array[x][y] = robot_array_bak[x][y];
}

/*----------------------------------------------------------------------*/
void
teleport()
{
  int num_wasted;

  if(!game_active) return;
  do
  {
    human_x = (int)random()%MAXX;        /* pick a spot not already occupied */
    human_y = (int)random()%MAXY;
  }
  while(robot_array[human_x][human_y] != EMPTY);

  show_teleport();

  num_wasted = chase();

  if(robot_array[human_x][human_y] != EMPTY)
  {
    /* death... */
    undo_chase();    
    /* it is a matter of preference to clear the screen when you die... */
    display_level();
    do_death();
    check_score(score);
    game_active = 0;
    return;
  }

  display_level();

  score += num_robots;       /* bonus for teleporting */
  score += num_wasted * 10;  /* score for any that collided */
  num_robots -= num_wasted;
  update_score(score);

  if(!num_robots) 
    new_level();
  else 
    display_possible_moves();

}

/*----------------------------------------------------------------------*/
void
sonic_screwdriver()
{
  /* remove the neighboring robots by calling chase(), then clear out */
  /* the human's position of robots */
  int num_wasted;

  if(!game_active) return;
  if(sonic_used) return;
  sonic_used = 1;
  show_sonic();
  num_wasted = chase();
  if(robot_array[human_x][human_y] == ROBOT)
    add_score(1);
  robot_array[human_x][human_y] = EMPTY;

  last_human_x = human_x;
  last_human_y = human_y;
  show_movement();

  add_score(num_wasted);
  if(!num_robots) 
    new_level();
  else 
    display_possible_moves();
}

/*----------------------------------------------------------------------*/
void
wait_for_em()
{
/* call chase until any robot is breathing right down the human's neck  */
  int num_wasted;

  if(!game_active) return;

  for(;;)
  {
    num_wasted = chase();
    if(!num_robots)
    {
      add_score(num_wasted);
      new_level();
      break;
    }
    if(robot_array[human_x][human_y] != EMPTY)
    {
      /* backout of latest chase() and break loop */
      undo_chase();
      break;
    }
    add_score(num_wasted);
    show_movement();
  }
  display_possible_moves();
}

/*----------------------------------------------------------------------*/


int
can_go(x,y)
  int x,y;
{
/* check if (x,y) is a legit move. */
  if( INYRANGE(y-1) ) {
    if( INXRANGE(x-1) )
      if(robot_array[x-1][y-1] == ROBOT)  return 0;
    if( INXRANGE(x) )
      if(robot_array[x][y-1] == ROBOT)  return 0;
    if( INXRANGE(x+1) )
      if(robot_array[x+1][y-1] == ROBOT)  return 0;
  }

  if( INYRANGE(y) ) {
    if( INXRANGE(x-1) )
      if(robot_array[x-1][y] == ROBOT)  return 0;
    if( INXRANGE(x) ) {
      if(robot_array[x][y] == ROBOT)  return 0;
      if(robot_array[x][y] == HEAP)   return 0;
      }
    if( INXRANGE(x+1) )
      if(robot_array[x+1][y] == ROBOT)  return 0;
  }

  if( INYRANGE(y+1) ) {
    if( INXRANGE(x-1) )
      if(robot_array[x-1][y+1] == ROBOT)  return 0;
    if( INXRANGE(x) )
      if(robot_array[x][y+1] == ROBOT)  return 0;
    if( INXRANGE(x+1) )
      if(robot_array[x+1][y+1] == ROBOT)  return 0;
  }

  if( !INXRANGE(x) )  return 0;
  if( !INYRANGE(y) )  return 0;

  return 1;
}

/*----------------------------------------------------------------------*/

SHAR_EOF
if test 6373 -ne "`wc -c < 'game.c'`"
then
	echo shar: error transmitting "'game.c'" '(should have been 6373 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'game.h'" '(934 characters)'
if test -f 'game.h'
then
	echo shar: will not over-write existing file "'game.h'"
else
cat << \SHAR_EOF > 'game.h'
/*
 * game.h  --  xrobots v1.0
 */

#ifndef MAXX
# 	define 	MAXX 35
#endif
#ifndef MAXY
#  	define 	MAXY 20
#endif

#define EMPTY 	0
#define ROBOT 	1
#define HEAP  	2
#define REDRAW 	3

#define LEFT    1
#define RIGHT   2
#define UP      4
#define DOWN    8
#define STILL   16

#define for_each	for(x=0;x<MAXX;x++) \
			  for(y=0;y<MAXY;y++)

/* I know, I KNOW... global variables! */

extern int 	human_x, human_y,
           	last_human_x, last_human_y;

extern int	robot_array[MAXX][MAXY],
		robot_array_bak[MAXX][MAXY];

extern int 	score;
		num_robots;
		game_active;

#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)

#define INXRANGE( _x_ )  (((_x_) >=0) && ((_x_)<MAXX))
#define INYRANGE( _y_ )  (((_y_) >=0) && ((_y_)<MAXY))

extern void 	new_game(), 
		add_score(), 
		new_level();
extern int  	chase();
extern void 	undo_chase(), 
		teleport(), 
		sonic_screwdriver(), 
		wait_for_em();
extern int  	can_go();




SHAR_EOF
if test 934 -ne "`wc -c < 'game.h'`"
then
	echo shar: error transmitting "'game.h'" '(should have been 934 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'graphics.c'" '(12072 characters)'
if test -f 'graphics.c'
then
	echo shar: will not over-write existing file "'graphics.c'"
else
cat << \SHAR_EOF > 'graphics.c'
/*
 * graphics.c  --  xrobots v1.0
 */

#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include "graphics.h"
#include "game.h"
#include "bitmaps.h"

static Pixmap playerP, dead_playerP, robotP, heapP, dotP;
static Cursor upC, up_rightC, rightC, down_rightC, downC, 
              down_leftC, leftC, up_leftC, stayC, cant_goC, thumbsC;

#define NUM_TMP_CURSOR_PIXMAPS 11
static Pixmap tmp_pixmap[NUM_TMP_CURSOR_PIXMAPS]; 

/*----------------------------------------------------------------------*/

void
init_pixmaps(top_shell)
  Widget top_shell;
{
/*
 * Let's make some pixmaps and some cursors.
 * And then let's set the iconpixmap.
 */
  Pixmap tmpP;
  XColor fgcolor,bgcolor;
  Arg arg;

  playerP = XCreateBitmapFromData(display,playfield, 
		Image_player_bits, Image_player_width, Image_player_height);

  dead_playerP = XCreateBitmapFromData(display,playfield, 
		Image_player_dead_bits, Image_player_dead_width, 
		Image_player_dead_height);

  robotP  = XCreateBitmapFromData(display,playfield, 
		Image_robot_bits, Image_robot_width, Image_robot_height);

  heapP   = XCreateBitmapFromData(display,playfield, 
		Image_heap_bits, Image_heap_width, Image_heap_height);

  dotP    = XCreateBitmapFromData(display,playfield, 
		dot_bits, dot_width, dot_height);

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

  fgcolor.pixel = fg;
  bgcolor.pixel = bg;
  fgcolor.flags =  DoRed | DoGreen | DoBlue;
  bgcolor.flags =  DoRed | DoGreen | DoBlue;
  XQueryColor(display,DefaultColormapOfScreen(XtScreen(playfield_widget)), &fgcolor);
  XQueryColor(display,DefaultColormapOfScreen(XtScreen(playfield_widget)), &bgcolor);


  tmp_pixmap[0] = 
  tmpP = XCreateBitmapFromData(display,playfield, up_bits, 
                                  up_width, up_height);
  upC  = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[1] = 
  tmpP = XCreateBitmapFromData(display,playfield, up_right_bits, 
                                  up_right_width, up_right_height);
  up_rightC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[2] = 
  tmpP = XCreateBitmapFromData(display,playfield, right_bits, 
                                  right_width, right_height);
  rightC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[3] = 
  tmpP = XCreateBitmapFromData(display,playfield, down_right_bits, 
                                  down_right_width, down_right_height);
  down_rightC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[4] = 
  tmpP = XCreateBitmapFromData(display,playfield, down_bits, 
                                  down_width, down_height);
  downC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[5] = 
  tmpP = XCreateBitmapFromData(display,playfield, down_left_bits, 
                                  down_left_width, down_left_height);
  down_leftC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[6] = 
  tmpP = XCreateBitmapFromData(display,playfield, left_bits, 
                                  left_width, left_height);
  leftC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[7] = 
  tmpP = XCreateBitmapFromData(display,playfield, up_left_bits, 
                                  up_left_width, up_left_height);
  up_leftC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[8] = 
  tmpP = XCreateBitmapFromData(display,playfield, stay_bits, 
                                  stay_width, stay_height);
  stayC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[9] = 
  tmpP = XCreateBitmapFromData(display,playfield, cant_go_bits, 
                                  cant_go_width, cant_go_height);
  cant_goC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,8,8);

  tmp_pixmap[10] = 
  tmpP = XCreateBitmapFromData(display,playfield, thumbs_down_bits, 
                                  thumbs_down_width, thumbs_down_height);
  thumbsC = XCreatePixmapCursor(display, tmpP, tmpP, &fgcolor,&bgcolor,
 				thumbs_down_x_hot,thumbs_down_y_hot);

  XtSetArg(arg,XtNiconPixmap,robotP);
  XtSetValues(top_shell,&arg,1);
}

/*----------------------------------------------------------------------*/

static void
display_ok_move(x,y)
  int x,y;
{

  if(can_go(x,y))
			/* show the icon for a good move */
    XCopyPlane(display,dotP,playfield,gc,0,0,
               dot_width,dot_height,
               pos_to_coord(x),pos_to_coord(y),1);
  else
			/* or erase any previous dross */
    if( INXRANGE(x) && INYRANGE(y) && (robot_array[x][y] == EMPTY))
      XClearArea(display, playfield, 
                 pos_to_coord(x), pos_to_coord(y),
                 CELLSIZE, CELLSIZE, False);
}

void
display_possible_moves()
{
  if(!spiffy) return;
  display_ok_move( human_x-1,human_y-1 );
  display_ok_move( human_x  ,human_y-1 );
  display_ok_move( human_x+1,human_y-1 );
  display_ok_move( human_x-1,human_y   );

  display_ok_move( human_x+1,human_y   );
  display_ok_move( human_x-1,human_y+1 );
  display_ok_move( human_x  ,human_y+1 );
  display_ok_move( human_x+1,human_y+1 );
}


void
display_level()
{
/* Naive refresh algorithm.... */
  int x,y;

  XClearWindow(display,playfield);
  if(game_active)
    XCopyPlane(display,playerP,playfield,gc,0,0,
 	Image_player_width,Image_player_height,
 	pos_to_coord(human_x),pos_to_coord(human_y),1);
  else
    XCopyPlane(display,dead_playerP,playfield,gc,0,0,
 	Image_player_dead_width,Image_player_dead_height,
 	pos_to_coord(human_x),pos_to_coord(human_y),1);

  for(y=0;y<MAXY;y++)
  {
    for(x=0;x<MAXX;x++)
        switch (robot_array[x][y])
        {
          case ROBOT:
            XCopyPlane(display,robotP,playfield,gc,0,0,
                       Image_robot_width,Image_robot_height,
                       pos_to_coord(x),pos_to_coord(y),1);
            break;

          case HEAP:  
            XCopyPlane(display,heapP,playfield,gc,0,0,
                       Image_heap_width,Image_heap_height,
                       pos_to_coord(x),pos_to_coord(y),1);
            break;
    }
  }
}


void
show_movement()
{
/* 
 * draw just the changes.
 */
  int x,y;

  /* force a redraw of the area surrounding last position */
  for(x=last_human_x-1;x<last_human_x+2;x++)
    for(y=last_human_y-1;y<last_human_y+2;y++)
      if( INXRANGE(x) && INYRANGE(y) )
        robot_array_bak[x][y] = REDRAW;  

  /* 
   * This is a little hacked up because the player isn't really in the 
   * robot array.  Assigning the backup array to EMPTY avoids
   * drawing over the player.
   */
  robot_array_bak[human_x][human_y] = EMPTY;   

  XCopyPlane(display,playerP,playfield,gc,0,0,
        Image_player_width,Image_player_height,
        pos_to_coord(human_x),pos_to_coord(human_y),1);

  for(y=0;y<MAXY;y++)
  {
    for(x=0;x<MAXX;x++)
      if(robot_array[x][y] != robot_array_bak[x][y])
        switch (robot_array[x][y])
        {
          case ROBOT:
            XCopyPlane(display,robotP,playfield,gc,0,0,
                       Image_robot_width,Image_robot_height,
                       pos_to_coord(x),pos_to_coord(y),1);
            break;

          case HEAP:
            XCopyPlane(display,heapP,playfield,gc,0,0,
                       Image_heap_width,Image_heap_height,
                       pos_to_coord(x),pos_to_coord(y),1);
            break;
          default:
            XClearArea(display, playfield, 
                       pos_to_coord(x), pos_to_coord(y),
                       CELLSIZE, CELLSIZE, False);
    }
  }
}



/*ARGSUSED*/
XtEventHandler
redisplay_level(w, closure, event)
  Widget w;
  caddr_t closure;
  XExposeEvent *event;
{
/* refresh entire screen -- e.g. expose events.  Just a little naive. */
  display_level();
  display_possible_moves();
}


void
update_pointer(direction)
  int direction;
{
/*
 * set the cursor to the appropriate one.
 */
  int tmp_human_x = human_x, tmp_human_y = human_y;

  if(direction & UP)    tmp_human_y--;
  if(direction & DOWN)  tmp_human_y++;
  if(direction & LEFT)  tmp_human_x--;
  if(direction & RIGHT) tmp_human_x++;

  if(!can_go(tmp_human_x,tmp_human_y)) {
    XDefineCursor(display,playfield,cant_goC);
    return;
    }
  if(direction&LEFT)
    if(direction&UP)
      XDefineCursor(display,playfield,up_leftC);
    else 
      if(direction&DOWN)
          XDefineCursor(display,playfield,down_leftC);
      else
        XDefineCursor(display,playfield,leftC);

   if(direction&RIGHT)
    if(direction&UP)
      XDefineCursor(display,playfield,up_rightC);
    else 
      if(direction&DOWN)
          XDefineCursor(display,playfield,down_rightC);
      else
        XDefineCursor(display,playfield,rightC);

  if(direction == UP)
        XDefineCursor(display,playfield,upC);
  if(direction == DOWN)
        XDefineCursor(display,playfield,downC);
  if(direction == STILL)
        XDefineCursor(display,playfield,stayC);
    

}


/*----------------------------------------------------------------------*/

void free_pixmaps()
{
  int i;

  XFreeCursor(display,upC);
  XFreeCursor(display,up_rightC);
  XFreeCursor(display,rightC);
  XFreeCursor(display,down_rightC);
  XFreeCursor(display,downC);
  XFreeCursor(display,down_leftC);
  XFreeCursor(display,leftC); 
  XFreeCursor(display,up_leftC); 
  XFreeCursor(display,stayC);
  XFreeCursor(display,thumbsC);
  XFreeCursor(display,cant_goC);
  for(i=0;i++;i<NUM_TMP_CURSOR_PIXMAPS) 
    XFreePixmap(display,tmp_pixmap[i]);

  XFreePixmap(display,playerP);
  XFreePixmap(display,dead_playerP);
  XFreePixmap(display,robotP);
  XFreePixmap(display,heapP);
  XFreePixmap(display,dotP);

}



/*----------------------------------------------------------------------*/

void
do_death()
{
  XDefineCursor(display,playfield,thumbsC);
  XCopyPlane(display,dead_playerP,playfield,gc,0,0,
 	Image_player_dead_width,Image_player_dead_height,
 	pos_to_coord(human_x),pos_to_coord(human_y),1);
}

/*----------------------------------------------------------------------*/

void
show_teleport()
{
/* 
 * This may need to be slowed down (or changed) if you have a fast server.
 * Looks okay on a sun 3/50.
 */
unsigned int i;

  if(!spiffy) return;

  for(i=100;i>0;i-=25)
    XDrawArc(display,playfield,gc,
      pos_to_coord(human_x)+(CELLSIZE/2)-(i/2)-2,
      pos_to_coord(human_y)+(CELLSIZE/2)-(i/2)-2,
      i,i,0,0);
}

/*----------------------------------------------------------------------*/

static void
do_sonic(agc)
GC agc;
{
/* 
 * do some effects for the sonic screwdriver...
 */
#define SPACING 3
int center_x = pos_to_coord(human_x)+(CELLSIZE/2)-2,
    center_y = pos_to_coord(human_y)+(CELLSIZE/2)-2;
int i;

  if(!spiffy) return;

  for(i=pos_to_coord(human_x-1);i<pos_to_coord(human_x+2);i+=SPACING) {
    XDrawLine(display,playfield,agc,center_x,center_y,i,pos_to_coord(human_y-1));
    XCopyPlane(display,playerP,playfield,gc,0,0,
 	Image_player_width,Image_player_height,
 	pos_to_coord(human_x),pos_to_coord(human_y),1);
  }

  for(i=pos_to_coord(human_y-1);i<pos_to_coord(human_y+2);i+=SPACING) {
    XDrawLine(display,playfield,agc,center_x,center_y,pos_to_coord(human_x+2),i);
    XCopyPlane(display,playerP,playfield,gc,0,0,
 	Image_player_width,Image_player_height,
 	pos_to_coord(human_x),pos_to_coord(human_y),1);
  }

  for(i=pos_to_coord(human_x+2);i>pos_to_coord(human_x-1);i-=SPACING) {
    XDrawLine(display,playfield,agc,center_x,center_y,i,pos_to_coord(human_y+2));
    XCopyPlane(display,playerP,playfield,gc,0,0,
 	Image_player_width,Image_player_height,
 	pos_to_coord(human_x),pos_to_coord(human_y),1);
  }

  for(i=pos_to_coord(human_y+2);i>pos_to_coord(human_y-1);i-=SPACING) {
    XDrawLine(display,playfield,agc,center_x,center_y,pos_to_coord(human_x-1),i);
    XCopyPlane(display,playerP,playfield,gc,0,0,
 	Image_player_width,Image_player_height,
 	pos_to_coord(human_x),pos_to_coord(human_y),1);
  }
}


void
show_sonic()
{
  do_sonic(gc);		/* do it, */
  do_sonic(cleargc);	/* then erase it. */
}

SHAR_EOF
if test 12072 -ne "`wc -c < 'graphics.c'`"
then
	echo shar: error transmitting "'graphics.c'" '(should have been 12072 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'graphics.h'" '(593 characters)'
if test -f 'graphics.h'
then
	echo shar: will not over-write existing file "'graphics.h'"
else
cat << \SHAR_EOF > 'graphics.h'
/*
 * graphics.h  --  xrobots v1.0
 */

 /* some of these are instanciated in main.c! */
extern Display 	*display;
extern Window 	playfield;
extern Widget 	playfield_widget;
extern GC 	gc,
		cleargc;
extern Pixel 	fg, 
		bg;
extern Boolean 	spiffy;

extern void 	update_score();

extern XtEventHandler redisplay_level();

extern void 	init_pixmaps(), 
		display_possible_moves(), 
		display_level(), 
		update_pointer(), 
		free_pixmaps(), 
		do_death(), 
		show_teleport(), 
		show_sonic(), 
		show_movement();

#define CELLSIZE 21

#define pos_to_coord( _pos_ ) (( _pos_ ) * CELLSIZE + 5)


SHAR_EOF
if test 593 -ne "`wc -c < 'graphics.h'`"
then
	echo shar: error transmitting "'graphics.h'" '(should have been 593 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'help.c'" '(3628 characters)'
if test -f 'help.c'
then
	echo shar: will not over-write existing file "'help.c'"
else
cat << \SHAR_EOF > 'help.c'
/*
 * help.c  --  xrobots v1.0
 */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/AsciiText.h>
#include <X11/Command.h>
#include <X11/Box.h>
#include "help.h"

/*----------------------------------------------------------------------*/

Widget help_popup;

static Arg arglist_text[] = {
  {  XtNheight, (XtArgVal) 300   },
  {  XtNtextOptions, (XtArgVal) scrollVertical },
  {  XtNwidth, (XtArgVal) 505 },
  {  XtNstring, (XtArgVal) "\
xrobots -- version 1.0\n\
\n\
Welcome to the world of xrobots.  Where the bad guys (the robots) are \n\
incredibly stupid and the good guy (the smiley face) is outnumbered.\n\
You (as the good guy) can avoid death and achieve instant fame and \n\
gratification by appropriate use of the mouse and/or keyboard.\n\
\n\
The mouse:  \n\
Clicking the left mouse button moves the smiley face one step in the \n\
direction of the pointer.  Clicking directly on top of the smiley face \n\
takes a turn, but does not change it's position.  \n\
\n\
Clicking the middle mouse button causes the smiley face to run like heck. \n\
Of course, the robots can run just as fast so it really doesn't matter... \n\
Or does it? \n\
\n\
Clicking the right mouse button gives the smiley a rest.  This is the \n\
same as clicking on the 'wait' button.\n\
\n\
\n\
The keyboard: \n\
	's' triggers the sonic screwdriver. \n\
	't' triggers the teleportation device. \n\
	'w' waits until robots are breathing down your neck. \n\
	'.' waits one turn. \n\
\n\
 	Directional control:\n\
\n\
		 y k u \n\
		  \\|/  \n\
		 h- -l \n\
		  /|\\  \n\
		 b j n \n\
\n\
\n\
Well, that's the low down.  If you don't like the mouse or keyboard set up,\n\
see the manual to find out about changing the translations.  \n\
\n\
----\n\
\n\
This insomnia killer was written by:\n\
  Brian Warkentine (bwarkent@polyslo.CalPoly.EDU).\n\
\n\ "
  },
  {  XtNeditType, (XtArgVal) XttextRead  },
};


static Arg arglist_popdown[] = {
  {  XtNresize, (XtArgVal) False  },
  {  XtNwidth, (XtArgVal) 300   },
  {  XtNlabel, (XtArgVal) "Pop Down"  },
  {  XtNjustify, (XtArgVal) XtJustifyCenter  },
};


/*ARGSUSED*/
static XtCallbackProc 
popdown_callback(w, closure, call_data)
  Widget w;
  caddr_t closure;
  caddr_t call_data;
{
  XtPopdown(help_popup);
}


void
create_help_popup(parent)
  Widget parent;
{
  int i;
  Widget help_box, popdown;

  help_popup = XtCreatePopupShell(
                                   "help_popup",
                                   transientShellWidgetClass,
                                   parent, 0,0);

  help_box = XtCreateManagedWidget(
                                    "help_box",
                                    boxWidgetClass,
                                    help_popup,
                                    0,0);

  (void) XtCreateManagedWidget(
                                    "message",
                                    asciiStringWidgetClass,
                                    help_box,
                                    arglist_text,
                                    XtNumber(arglist_text));

  popdown = XtCreateManagedWidget(
                                    "popdown",
                                    commandWidgetClass,
                                    help_box,
                                    arglist_popdown,
                                    XtNumber(arglist_popdown));
  XtAddCallback(popdown,XtNcallback,popdown_callback,0);
}



/*ARGSUSED*/
XtCallbackProc
show_help_callback(widget,closure,callData)
  Widget widget;
  caddr_t closure;
  caddr_t callData;
{
  XtPopup(help_popup, XtGrabNone);
}



SHAR_EOF
if test 3628 -ne "`wc -c < 'help.c'`"
then
	echo shar: error transmitting "'help.c'" '(should have been 3628 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'help.h'" '(116 characters)'
if test -f 'help.h'
then
	echo shar: will not over-write existing file "'help.h'"
else
cat << \SHAR_EOF > 'help.h'
/*
 * help.h  --  xrobots v1.0
 */

extern void 		create_help_popup();
extern XtCallbackProc	show_help_callback();

SHAR_EOF
if test 116 -ne "`wc -c < 'help.h'`"
then
	echo shar: error transmitting "'help.h'" '(should have been 116 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'main.c'" '(8713 characters)'
if test -f 'main.c'
then
	echo shar: will not over-write existing file "'main.c'"
else
cat << \SHAR_EOF > 'main.c'
/*
 * main.c  --  xrobots v1.0
 * 
 * Author: Brian Warkentine, 1989.
 *
 * Permission to use, copy, modify and distribute (without charge) this
 *   software, documentation, images, etc. is granted, provided that this 
 *   comment and the author's name is retained.  The author assumes no 
 *   responsibility for lost sleep as a consequence of use of this software.
 *
 * Send comments, bug reports, etc. to bwarkent@polyslo.CalPoly.EDU.
 *   (Soon to be at @Sun.COM, so if the previous address doesn't work,
 *   try brian@csufres.CSUFresno.EDU.)
 *
 * Portions of this code generated by wedgimatic on Jan 21 14:24:10 PST 1989.
 * 
 */

#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/Core.h>
#include <X11/Label.h>
#include <X11/Command.h>
#include <X11/Box.h>

#include "callbacks.h"
#include "graphics.h"
#include "game.h"
#include "score.h"
#include "help.h"

/*----------------------------------------------------------------------*/

Widget top_shell, top_widget, playfield_widget, score_widget, sonic_command;

Display *display;
Window playfield;

GC gc;
GC cleargc;

/*----------------------------------------------------------------------*/


static XtCallbackRec teleport_callbackList[] = {
  {  (XtCallbackProc)teleport_callback, NULL  },
  {  NULL, NULL  }
};

static XtCallbackRec wait_callbackList[] = {
  {  (XtCallbackProc)wait_callback, NULL  },
  {  NULL, NULL  }
};

static XtCallbackRec sonic_callbackList[] = {
  {  (XtCallbackProc)sonic_callback, NULL  },
  {  NULL, NULL  }
};

static XtCallbackRec quitList[] = {
  {  (XtCallbackProc)quit_callback, NULL  },
  {  NULL, NULL  }
};

static XtCallbackRec new_gameList[] = {
  {  (XtCallbackProc)new_game_callback, NULL  },
  {  NULL, NULL  }
};

static XtCallbackRec show_helpList[] = {
  {  (XtCallbackProc)show_help_callback, NULL  },
  {  NULL, NULL  }
};

/*----------------------------------------------------------------------*/


static Arg arglistplayfield[] = {
  {  XtNheight, (XtArgVal) pos_to_coord(MAXY)  },
  {  XtNwidth,  (XtArgVal) pos_to_coord(MAXX)  },
  {  XtNborderWidth, (XtArgVal) 4 },
};

static Arg arglistteleport_command[] = {
  {  XtNlabel, (XtArgVal) "Teleport"  },
  {  XtNcallback, (XtArgVal) teleport_callbackList }
};

static Arg arglistwait_command[] = {
  {  XtNlabel, (XtArgVal) "Wait"  },
  {  XtNcallback, (XtArgVal) wait_callbackList }
};

static Arg arglistsonic_command[] = {
  {  XtNlabel, (XtArgVal) "Sonic Screwdriver"  },
  {  XtNcallback, (XtArgVal) sonic_callbackList }
};

static Arg arglistquit_command[] = {
  {  XtNlabel, (XtArgVal) "Quit"  }, 
  {  XtNcallback, (XtArgVal) quitList }
};

static Arg arglistnew_game[] = {
  {  XtNlabel, (XtArgVal) "New Game"  }, 
  {  XtNcallback, (XtArgVal) new_gameList }
};

static Arg arglistscore_widget[] = {
  {  XtNlabel, (XtArgVal) "Score:    0"  }, 
};

static Arg arglisthelp_button[] = {
  {  XtNlabel, (XtArgVal) "Help"  }, 
  {  XtNcallback, (XtArgVal) show_helpList }
};

/*----------------------------------------------------------------------*/

/* these can be overriden -- of course */
static char translations_str[] = 
  "<Btn1Down>:	do_nothing()		\n\
   <Btn2Down>:	do_nothing()		\n\
   <Btn3Down>:	do_nothing()		\n\
   <Btn1Up>:    move()			\n\
   <Key>u:      move(right, up)		\n\
   <Key>l:      move(right)		\n\
   <Key>n:      move(right, down)	\n\
   <Key>y:      move(left, up)		\n\
   <Key>h:      move(left)		\n\
   <Key>b:      move(left, down)	\n\
   <Key>k:      move(up)		\n\
   <Key>j:      move(down)		\n\
   <Key>.:      move(nowhere)		\n\
   <Key>\\ :    move(nowhere)		\n\
   <Btn2Up>:    go_here() 		\n\
   <Btn3Up>:    wait()	 		\n\
   <Key>s:      sonic()			\n\
   <Key>t:      teleport() 		\n\
   <Key>w:      wait()			\n\
   <Key>z:      new_game()		";
/* <Key>q:      quit() "; */

Pixel fg, bg;
Boolean spiffy;
XtTranslations translations;

static XtResource application_resources[] = {
  {"foreground", "Foreground", XtRPixel, sizeof(Pixel),
                (Cardinal)&fg, XtRString, (caddr_t) "Black"},
  {"background", "Background", XtRPixel, sizeof(Pixel),
                (Cardinal)&bg, XtRString, (caddr_t) "White"},
  {"spiffy", "Spiffy", XtRBoolean, sizeof(Boolean),
                (Cardinal)&spiffy, XtRString, (caddr_t) "True"},
  {"translations","Translations", XtRTranslationTable, sizeof(XtTranslations),
                (Cardinal)&translations, XtRString, (caddr_t)translations_str},
};

/*----------------------------------------------------------------------*/

main(argc, argv)
  unsigned int argc;
  char **argv;
{
  Arg args[1];
  XGCValues gcv;

  srandom(getpid());

  top_shell = XtInitialize(argv[0], "xrobots", 0, 0, &argc, argv);

  init_actions();

  XtGetApplicationResources(top_shell, 0, application_resources, 
			XtNumber(application_resources), NULL, 0 );

  top_widget = XtCreateManagedWidget(
                                    "top_widget",
                                    boxWidgetClass,
                                    top_shell,
                                    0,0);

  playfield_widget = XtCreateManagedWidget(
                                    "playfield",
                                    widgetClass,
                                    top_widget,
                                    arglistplayfield,
                                    XtNumber(arglistplayfield));

  XtAugmentTranslations(playfield_widget,translations);

  (void) XtCreateManagedWidget(
                                    "teleport_button",
                                    commandWidgetClass,
                                    top_widget,
                                    arglistteleport_command,
                                    XtNumber(arglistteleport_command));

  (void) XtCreateManagedWidget(
                                    "wait_button",
                                    commandWidgetClass,
                                    top_widget,
                                    arglistwait_command,
                                    XtNumber(arglistwait_command));

  sonic_command= XtCreateManagedWidget(
                                    "sonic_button",
                                    commandWidgetClass,
                                    top_widget,
                                    arglistsonic_command,
                                    XtNumber(arglistsonic_command));

  (void) XtCreateManagedWidget(
                                    "quit_button",
                                    commandWidgetClass,
                                    top_widget,
                                    arglistquit_command,
                                    XtNumber(arglistquit_command));
  (void) XtCreateManagedWidget(
                                    "new_game_button",
                                    commandWidgetClass,
                                    top_widget,
                                    arglistnew_game,
                                    XtNumber(arglistnew_game));

  (void) XtCreateManagedWidget(
                                    "help_button",
                                    commandWidgetClass,
                                    top_widget,
                                    arglisthelp_button,
				    XtNumber(arglisthelp_button));

  score_widget = XtCreateManagedWidget(
                                    "score_button",
                                    labelWidgetClass,
                                    top_widget,
                                    arglistscore_widget,
                                    XtNumber(arglistscore_widget));


  create_high_score_popup(top_widget);
  create_help_popup(top_widget);

  XtRealizeWidget(top_shell);

  display   = XtDisplay(playfield_widget);
  playfield = XtWindow(playfield_widget);
  gcv.foreground = fg;
  gcv.background = bg;
  gcv.function = GXcopy;
  gc = XCreateGC(display, playfield, 
 		GCForeground | GCBackground | GCFunction, &gcv);
  gcv.foreground = bg;
  cleargc = XCreateGC(display, playfield,
 		 GCForeground | GCBackground | GCFunction, &gcv);

  XtAddEventHandler(playfield_widget, ExposureMask, 0, redisplay_level, 0);
  XtAddEventHandler(playfield_widget, PointerMotionMask, 0, pointer_moved, 0);

  init_pixmaps(top_shell);

  new_game();

  XtMainLoop();

}


void
quit_game()
{
  free_pixmaps();
  XtDestroyWidget(top_shell);
  XFreeGC(display,gc);
  XFreeGC(display,cleargc);

/*  XtDestroyApplicationContext(); */
  exit(0);
}


void
update_score(score)
  int score;
{
  char text[13];
  (void)sprintf(text,"Score: %4d",score);
  XtSetArg(arglistscore_widget[0],XtNlabel,text);
  XtSetValues(score_widget,arglistscore_widget,1);
}



SHAR_EOF
if test 8713 -ne "`wc -c < 'main.c'`"
then
	echo shar: error transmitting "'main.c'" '(should have been 8713 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'score.c'" '(5337 characters)'
if test -f 'score.c'
then
	echo shar: will not over-write existing file "'score.c'"
else
cat << \SHAR_EOF > 'score.c'
/*
 * score.c  --  xrobots v1.0
 *
 * flock() is used to stop a race condition within... if you don't 
 * have a bsd-like flock(), you could probably comment it out.
 * The race condition (multiple users writing to the score file) is 
 * probably rare.
 */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Box.h>
#include <X11/Command.h>
#include <X11/Label.h>
#include <stdio.h>
#include <sys/file.h>
#include "score.h"
#include "game.h"

/*----------------------------------------------------------------------*/

typedef struct {
  char 	score[6], 
	name[26];
} SCORE;

static SCORE scores[MAXSCORES];

void 	show_scores(), 
	new_high_score(), 
	load_scores(), 
	write_out_scores();

static FILE *scorefile = 0;

/*----------------------------------------------------------------------*/

void
check_score(current_score)
  int current_score;
{

  load_scores();

  if(current_score > atoi(scores[MAXSCORES-1].score)) {
    new_high_score(current_score);
    write_out_scores();
  }
  if(scorefile) {
    flock(scorefile->_file, LOCK_UN);
    fclose(scorefile);
    show_scores();
  }
}


static void
load_scores()
{
  int i = 0;

  if( !(scorefile = fopen(SCORE_FILE,"r+")) ) {
    scorefile = fopen(SCORE_FILE, "w");
    return;
  }
  flock(scorefile->_file, LOCK_EX);
  while( fgets(scores[i].score,6,scorefile) 	/* get score */
      && fgets(scores[i].name,26,scorefile) 	/* get name */
      && fgetc(scorefile))			/* and newline */
  {
    i++;
    if( i > MAXSCORES ) break;
  }
}


static void
new_high_score(current_score)
  int current_score;
{
  int i;
  char textscore[6],
       name[26];

  sprintf(textscore,"%5d",current_score);
  strncpy(name,getenv("USER"),25);

  for(i=MAXSCORES-2;i>=0;i--)
    if( current_score < atoi(scores[i].score) ) {
         /* move new score into i+1 slot */
      strcpy(scores[i+1].score,textscore);
      strcpy(scores[i+1].name,name);
      return;
    } else {
      strcpy(scores[i+1].score,scores[i].score);
      strcpy(scores[i+1].name,scores[i].name);
    }
  /* if it got here, there is a new number 1 score */
  strcpy(scores[0].score,textscore);
  strcpy(scores[0].name,name);

}


static void
write_out_scores()
{
  int i;

  if( !scorefile )
    return;
  rewind(scorefile);
  for(i=0;i<MAXSCORES;i++)
    fprintf(scorefile,"%5s%25s\n",scores[i].score,scores[i].name);
}


/*----------------------------------------------------------------------*/


Widget score_popup;
Widget score_labels[MAXSCORES];

static Arg arglist_score_title[] = {
  {  XtNborderWidth, (XtArgVal) 0  },
  {  XtNresize, (XtArgVal) False  },
  {  XtNwidth, (XtArgVal) 300   },
  {  XtNheight, (XtArgVal) 30   },
  {  XtNlabel, (XtArgVal) "High Scores"  },
  {  XtNjustify, (XtArgVal) XtJustifyCenter  },
};

static Arg arglist_score_label[] = {
  {  XtNlabel, (XtArgVal) 0  },
  {  XtNborderWidth, (XtArgVal) 0  },
  {  XtNresize, (XtArgVal) False  },
  {  XtNwidth, (XtArgVal) 300   },
  {  XtNjustify, (XtArgVal) XtJustifyCenter  },
};

static Arg arglist_popdown[] = {
/*  {  XtNborderWidth, (XtArgVal) 2  },*/
  {  XtNresize, (XtArgVal) False  },
  {  XtNwidth, (XtArgVal) 300   },
  {  XtNlabel, (XtArgVal) "Pop Down"  },
  {  XtNjustify, (XtArgVal) XtJustifyCenter  },
};


/*ARGSUSED*/
static XtCallbackProc 
popdown_callback(w, closure, call_data)
  Widget w;
  caddr_t closure;
  caddr_t call_data;
{
  XtPopdown(score_popup);
}


void
create_high_score_popup(parent)
  Widget parent;
{
  int i;
  Widget score_box, popdown;

  score_popup = XtCreatePopupShell(
                                   "score_popup",
                                   transientShellWidgetClass,
                                   parent, 0,0);

  score_box = XtCreateManagedWidget(
                                    "score_box",
                                    boxWidgetClass,
                                    score_popup,
                                    0,0);

  (void)XtCreateManagedWidget(
                                    "score_title",
                                    labelWidgetClass,
                                    score_box,
                                    arglist_score_title,
                                    XtNumber(arglist_score_title));

  for(i=0;i<MAXSCORES;i++) {
    score_labels[i] = XtCreateManagedWidget(
                                    "alabel",
                                    labelWidgetClass,
                                    score_box,
                                    arglist_score_label,
                                    XtNumber(arglist_score_label));
  }

  popdown = XtCreateManagedWidget(
                                    "popdown",
                                    commandWidgetClass,
                                    score_box,
                                    arglist_popdown,
                                    XtNumber(arglist_popdown));
  XtAddCallback(popdown,XtNcallback,popdown_callback,0);
}



void
show_scores()
{
  int i;
  char tmp_str[31];
  Arg tmp_arg;

  for(i = 0;i<MAXSCORES;i++) {
    sprintf(tmp_str,"%5s  %25s", scores[i].score, scores[i].name);
    XtSetArg(tmp_arg,XtNlabel,tmp_str);
    XtSetValues(score_labels[i],&tmp_arg,1);
  }
  XtPopup(score_popup, XtGrabNone);
}


/*----------------------------------------------------------------------*/

SHAR_EOF
if test 5337 -ne "`wc -c < 'score.c'`"
then
	echo shar: error transmitting "'score.c'" '(should have been 5337 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'score.h'" '(225 characters)'
if test -f 'score.h'
then
	echo shar: will not over-write existing file "'score.h'"
else
cat << \SHAR_EOF > 'score.h'
/*
 * score.h  --  xrobots v1.0
 */

#ifndef SCORE_FILE
#  define SCORE_FILE "/usr/games/lib/xrobots_scores"
#endif

#ifndef MAXSCORES
#  define MAXSCORES 20
#endif

extern void 	check_score(), 
		create_high_score_popup();

SHAR_EOF
if test 225 -ne "`wc -c < 'score.h'`"
then
	echo shar: error transmitting "'score.h'" '(should have been 225 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xrobots.man'" '(4066 characters)'
if test -f 'xrobots.man'
then
	echo shar: will not over-write existing file "'xrobots.man'"
else
cat << \SHAR_EOF > 'xrobots.man'
.\" Man page for xrobots.
.TH XROBOTS 6 "11 May 1989"
.SH NAME
xrobots \- fight off villainous robots (X Windows)
.SH SYNOPSIS
.B /usr/games/xrobots 
.SH DESCRIPTION
.LP
As in robots(6), xrobots puts you into a world of evil robots (but in
an X window, of course).
It's your intellect against the robots, who have numbers on their side.
Fortunately for you, these robots have a bad habit of crashing into 
each other, destroying themselves and putting you in a better position
to survive.
.LP
You have a the following abilities: 
.LP
.RS
You can move one square at a time (but so can the robots).  
These directions are indicated by diamonds near your man.
Clicking the left mouse button selects the direction.
.LP
You can wait for robots to reach you.  Do this by clicking on
the button labeled "Wait" below the main playfield or by 
pressing 'w' while the mouse pointer is within the playfield.
.LP
You can use your teleportation device.  This defensive weapon
is not without risk.  This can be invoked by clicking on 
"Teleport" or by pressing 't'.
.LP
You have a "sonic screwdriver" which wipes out any robots 
within close proximity.  This offensive weapon recharges once for 
each level.  This can be invoked by the "Sonic Screwdiver" button
or by pressing 's'.
.RE
.LP
.SH RESOURCES
.LP
If you don't like 's' for the sonic screwdriver and 't' for teleport
you can change this.  xrobots is programmed using the X Toolkit and 
takes advantage of the toolkit's resources and translation schemes.  
For example, if you don't want all the spiffy graphics, place
the following line in your .Xdefaults file.
.LP
.RS
xrobots.spiffy: false
.RE
.LP
The default for this resource is true.
.LP
Additionally, all the key bindings can be changed.  Here's a sample
set of translation bindings:
.LP
.RS
xrobots*Translations:   #augment     \\n\\ 
.RS
.nf
<Btn1Up>:    move()             \\n\\ 
<Key>u:      move(right, up)    \\n\\ 
<Key>l:      move(right)        \\n\\ 
<Key>n:      move(right, down)  \\n\\ 
<Key>y:      move(left, up)     \\n\\ 
<Key>h:      move(left)         \\n\\ 
<Key>b:      move(left, down)   \\n\\ 
<Key>k:      move(up)           \\n\\ 
<Key>j:      move(down)         \\n\\ 
<Key>.:      move(nowhere)      \\n\\ 
<Key>\\\\ :    move(nowhere)      \\n\\ 
<Btn2Up>:    go_here()          \\n\\ 
<Btn3Up>:    wait()             \\n\\ 
<Key>s:      sonic()            \\n\\ 
<Key>t:      teleport()         \\n\\ 
<Key>w:      wait()             \\n\\ 
<Key>z:      new_game()         \\n\\ 
:<Key>Q:      quit()
.fi
.RE
.RE
.RE
.LP
Of course, these defaults should copied into your .Xdefaults file to
take effect.  You studs out there might even use xrdb(1).
.LP
.SH ACTIONS
.LP
Here's what each action is and what it does:
.RS
.LP
The move() action with no parameters uses the relative position of the 
mouse pointer to determine the direction in which to go.  Otherwise,
a combination of "left", "right", "up", "down", and "nowhere" will 
direct the direction.  If "nowhere" is used, the player's icon will
remain still while the robots take their turn.
.LP
The go_here() action directs the player's icon to the location where the
mouse button was released.  Of course, the robots will chase you, and
if doom is impending, go_here() will stop.
.LP 
The wait() action causes the robots to move until they are breathing
right down your neck.
.LP  
The sonic() action invokes the sonic screwdriver.
.LP
The teleport() action invokes the teleportation device.
.LP
The new_game() and quit() actions do what you would expect them to. 
.LP
.SH SCORING
.LP
Each robot that is wasted is worth ten points.  Additionally, 
bonuses are awarded for each teleportation, and for not using the 
sonic screwdriver.  The name for the high score list comes from
the USER environment variable.
.LP
.SH FILES
.LP
/usr/games/lib/xrobots_scores \-\- the score file
.LP
.SH AUTHOR
.LP
There are many versions of robots floating around.  So many that it
would be difficult to say who the original author is.  This version was
written from scratch by Brian Warkentine.

SHAR_EOF
if test 4066 -ne "`wc -c < 'xrobots.man'`"
then
	echo shar: error transmitting "'xrobots.man'" '(should have been 4066 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0