[comp.windows.x] xfish - a useless diversion

bradley@dsl.cis.upenn.edu (John Bradley) (06/08/87)

This program performs the valuable (?) task of putting fish on your screen.
I've compiled it on an IBM RT PC running 4.2, and a MicroVax GPX II running
Ultrix 2.0.  Works just dandy on those.  Probably should on any other 4.2-ish
Unix machine.

John Bradley  -  bradley@cis.upenn.edu

-------------------(cut here)-------------------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\Rogue\Monster\'
Notes on 'xfish':

Xfish is a program that opens a window that, for all intents and purposes,
appears to be the root window, except for the minor fact that there's now
fish swimming around in it.  It also has the added benefit of instantly 
raising your load average by 1 unit.  If you're doing it over a network, it
even simulates heavy network traffic.  It's the program that does it all, 
provided you define 'all' as meaning 'puts fish on the screen'.

You can specify the number of fish, from 1 to 100.  The default is 20.

If you grow bored with having fish flapping around on your desktop, you can
poke them with the left button.  This will cause the fish to feep at you, and
turn around.

If you grow tired of annoying fish, you can just blow the suckers away by 
shooting them with the right button.

Important Fish-Blastin' Tip:  You have to lead the fish, as there's a delay
between the time the mouse is clicked, and the time that the program finds
out that the mouse was clicked.  The time is fairly constant, so the faster
a fish is moving, the more you have to lead it.  Shooting the last two or
three fishes is mostly a matter of luck.  And superior firepower.

When you've blasted all the fish, it'll print give you your seconds-per-fish
ratio.  It's more fun to compete.  Play flipper skill games for fun and 
excitement.

John Bradley, 
Graphics Weenie
University of Pennsylvania

(bradley@cis.upenn.edu)

\Rogue\Monster\
else
  echo "will not over write ./README"
fi
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\Rogue\Monster\'
INCLUDES = 

XLIB = /usr/lib/libX.a
CFLAGS = $(INCLUDES)
CLIBS = 

.SUFFIXES: .o .h .c .a

OBJS = xfish.o

all: xfish

xfish: $(OBJS)
	cc $(CFLAGS) -o xfish $(OBJS) $(XLIB) $(CLIBS)

\Rogue\Monster\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./xfish.c`
then
echo "writing ./xfish.c"
cat > ./xfish.c << '\Rogue\Monster\'
/*
 * xfish.c  -  serves no useful purpose whatsoever
 *
 *  Author:    John H. Bradley, University of Pennsylvania
 *                (bradley@cis.upenn.edu)
 *                     March, 1987
 */


#include <stdio.h>
#include <math.h>
#include <strings.h>
#include <signal.h>
#include <X/Xlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/timeb.h>


/* handy-dandy functions */
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? -(a) : (a))


/* colors */
int ForeColor, BackColor;

/* objects */
Window   theWindow;
Bitmap   fishBMask,fishrBMask,stipB;
Pixmap   stipP;
Cursor   curs;


#define cross_width 16
#define cross_height 16
#define cross_x_hot 7
#define cross_y_hot 7
static short cross_bits[] = {      /* fish-zappin' cursor */
   0x0000, 0x03e0, 0x0c98, 0x1084,
   0x1414, 0x2082, 0x2082, 0x3b6e,
   0x2082, 0x2082, 0x1414, 0x1084,
   0x0c98, 0x03e0, 0x0000, 0x0000};

static short cross_mask_bits[] = {
   0x07e0, 0x0ff8, 0x1ffc, 0x3ffe,
   0x3ffe, 0x7fff, 0x7fff, 0x7fff,
   0x7fff, 0x7fff, 0x3ffe, 0x3ffe,
   0x1ffc, 0x0ff8, 0x03e0, 0x0000};


#define fish_width 32
#define fish_height 16
static short fish_bits[32] =       /* a left-going fish */
  {0xc000, 0x0007, 0xb000, 0x0006,
   0x7f80, 0xe003, 0x8260, 0xb003,
   0x0018, 0x680c, 0x0264, 0x37f0,
   0x0062, 0x2800, 0xaa01, 0x36aa,
   0x0046, 0x2800, 0x0338, 0x5fc0,
   0x28b0, 0xb030, 0x39c0, 0xe00e,
   0xee00, 0x0001, 0x5000, 0x0000,
   0xa000, 0x0000, 0xc000, 0x0000};


static short fish_mask_bits[32] = 
  {0xc000, 0x0007, 0xf000, 0x0007,
   0xff80, 0xe003, 0xffe0, 0xf003,
   0xfff8, 0x780f, 0xfffc, 0x3fff,
   0xfffe, 0x3fff, 0xffff, 0x3fff,
   0xfffe, 0x3fff, 0xfff8, 0x7fff,
   0xfff0, 0xf03f, 0xffc0, 0xe00f,
   0xfe00, 0x0001, 0x7000, 0x0000,
   0xe000, 0x0000, 0xc000, 0x0000};

static short fishr_bits[32] =        /* a right-going fish */
  {0xe000, 0x0003, 0x6000, 0x000d,
   0xc007, 0x01fe, 0xc00d, 0x0641,
   0x3012, 0x1800, 0x0fec, 0x2640,
   0x0014, 0x4600, 0xaaac, 0x804a,
   0x0014, 0x6200, 0x03fa, 0x1cc0,
   0x0c0d, 0x0d14, 0x7007, 0x039c,
   0x8000, 0x0077, 0x0000, 0x000a,
   0x0000, 0x0005, 0x0000, 0x0003};

static short fishr_mask_bits[32] = 
  {0xe000, 0x0003, 0xe000, 0x000f,
   0xc007, 0x01ff, 0xc00f, 0x07ff,
   0xf01e, 0x1fff, 0xfffc, 0x3fff,
   0xfffc, 0x7fff, 0xfffc, 0xffff,
   0xfffc, 0x7fff, 0xfffe, 0x1fff,
   0xfc0f, 0x0fff, 0xf007, 0x03ff,
   0x8000, 0x007f, 0x0000, 0x000e,
   0x0000, 0x0007, 0x0000, 0x0003};


#define MAXFISH 100
struct fishstr {  short x,y,dx,dy,fnum;  } fish[MAXFISH];

int NUMFISH=20, startnfish=20, shots=0;

/* checkerboard pattern (theoretically the same as the Root Window pattern) */
static short check_bits[] = {
   0xeeee, 0xdddd, 0x7777, 0xbbbb,
   0xeeee, 0xdddd, 0x7777, 0xbbbb,
   0xeeee, 0xdddd, 0x7777, 0xbbbb,
   0xeeee, 0xdddd, 0x7777, 0xbbbb};

long starttime;

/**************/
main(argc, argv)
    int   argc;
    char *argv[];
/**************/
{
    int i,dpcs,n;
    char *strind;

    char *fc, *bc;
    char *display = NULL;
    int rvflag    = 0;      /* don't use reverse video as a default */

    Color cdef;
    WindowInfo winfo;

    char *def;
    short bot,right;


    /*********************Defaults*********************/
    
    if ((def=XGetDefault(argv[0],"ReverseVideo"))!=NULL)
         if (strcmp(def,"on")==0) rvflag=1;

    fc  = XGetDefault(argv[0], "Foreground");
    bc  = XGetDefault(argv[0], "Background");


    /*********************Options*********************/

    for (i = 1; i < argc; i++) {

        strind = index(argv[i], ':');       /* is it display address? */
        if(strind != NULL) {
            display = argv[i];
            continue;
            }

        if (strcmp(argv [i], "-rv") == 0) {
            rvflag++;
            continue;
            }

        if (n=atoi(argv[i])) {
            if (n<1) n=1;
            if (n>100) n=100;
            NUMFISH=startnfish=n;
            continue;
            }

        Syntax(argv[0]);
    }


    /*****************************************************/

    /* Open up the display. */

    if (XOpenDisplay(display) == NULL) {
        fprintf(stderr, "%s: Can't open display '%s'\n",
                         argv[0], DisplayName());
        exit(1);
        }

    

    /* Set normal default colors */
    if (!rvflag) { ForeColor=BlackPixel;  BackColor=WhitePixel; }
            else { ForeColor=WhitePixel;  BackColor=BlackPixel; }


    /* Set up colors and pixmaps. */
    dpcs=DisplayCells();
    if (dpcs>2&&(fc !=NULL)&&XParseColor(fc ,&cdef)&&XGetHardwareColor(&cdef))
        ForeColor=cdef.pixel;

    if (dpcs>2&&(bc !=NULL)&&XParseColor(bc ,&cdef)&&XGetHardwareColor(&cdef))
        BackColor=cdef.pixel;


    /* Open the main window. */
    {
    int min_width, min_height;
    char default_geom[20];
    OpaqueFrame frame;
    
    min_width  = DisplayWidth();
    min_height = DisplayHeight();
    sprintf (default_geom, "%dx%d+0+0", min_width, min_height);

    stipB = XStoreBitmap(16,16,check_bits);
    stipP = XMakePixmap(stipB,ForeColor,BackColor);

    frame.bdrwidth   = 2;
    frame.border     = XMakeTile(ForeColor);
    frame.background = stipP;

    theWindow = XCreate("Fishies",argv[0],default_geom,default_geom,
                          &frame,min_width,min_height);

    if (!theWindow) XFishError("Can't open fish window");
    }

    XQueryWindow(theWindow,&winfo);
    bot=winfo.height;  right=winfo.width;
    
    XMapWindow    (theWindow);
    XLowerWindow  (theWindow);

    fishBMask =XStoreBitmap(fish_width,fish_height,fish_mask_bits);
    fishrBMask=XStoreBitmap(fish_width,fish_height,fishr_mask_bits);
    
    /* init fish */
    for (i=0; i<NUMFISH; i++) {
        fish[i].x=rand()%(right-100)+50;
        fish[i].y=rand()%(bot-100)+50;
        fish[i].dx = (abs(rand()%4)+3);
        if ((rand()%5)==0) fish[i].dx += 5;  /* hyper fish */

        /* switch direction based on a higher-order bit.  the low-order bit
           tended to be useless */
        if (rand()&0x10) fish[i].dx = -fish[i].dx;  

        fish[i].dy=rand()%7-3;  if (fish[i].dy==0) fish[i].dy=1;
        }

    XSelectInput(theWindow,ButtonPressed);
    curs = XCreateCursor(cross_width,cross_height,cross_bits,
                         cross_mask_bits, cross_x_hot, cross_y_hot,
                         ForeColor, BackColor, GXcopy);

    XDefineCursor(theWindow,curs);

    starttime=time(0);
    /**************** Main loop *****************/

    while (1) {
        XEvent event;
        short  x,y,bnum;

        if (XPending()) {
            XNextEvent(&event);
            if (event.type == ButtonPressed) {
                XButtonEvent *butevent = (XButtonEvent *) &event;

                bnum = butevent->detail & 0xff;
                if ((bnum == LeftButton) || (bnum == RightButton)) {

                    if (bnum == RightButton) shots++;

                    /* find out what fishy was hit */

                    x = butevent->x;  y = butevent->y;
                    for (i=0; i<NUMFISH; i++) {
                        if ( (x >= fish[i].x) &&
                             (x <= fish[i].x+fish_width) &&
                             (y >= fish[i].y) &&
                             (y <= fish[i].y+fish_height) ) break;
                        }

                    if (i!=NUMFISH) {  /* found one */
                        XFeep(0);
                        EraseFish(i);
                        if (bnum == LeftButton) {  /* bounce fish */
                            fish[i].dx = -fish[i].dx;
                            fish[i].dy = -fish[i].dy;
                            DrawFish(i);
                            }
                        else {                     /* destroy fish */
                            if (NUMFISH==1) Stats();
                            bcopy(&fish[NUMFISH-1],&fish[i],
                                  sizeof(struct fishstr));
                            NUMFISH--;
                            }
                        }
                    }
                }
           }

        /* move fish */
        for (i=0; i<NUMFISH; i++) {
            EraseFish(i);

            fish[i].x += fish[i].dx;
            fish[i].y += fish[i].dy;
            if (fish[i].x < -50 || fish[i].x > (right+50))
                fish[i].dx = -fish[i].dx;
            if (fish[i].y < 0 || fish[i].y > (bot-16))
                fish[i].dy = -fish[i].dy;

            DrawFish(i);
            }
        Timer(100000L);
    }  /* end main loop */
}

/*****************/
EraseFish(i)
      int i;
{
    if (fish[i].dx<0)
        XTileFill(theWindow,fish[i].x,fish[i].y,fish_width,fish_height,
                    stipP,fishBMask,GXcopy,AllPlanes);
    else
        XTileFill(theWindow,fish[i].x,fish[i].y,fish_width,fish_height,
                    stipP,fishrBMask,GXcopy,AllPlanes);
}

/*****************/
DrawFish(i)
     int i;
{
    if (fish[i].dx<0) 
        XBitmapBitsPut(theWindow,fish[i].x,fish[i].y,
            fish_width,fish_height,fish_bits,ForeColor,BackColor,
            fishBMask,GXcopy,AllPlanes);
    else
        XBitmapBitsPut(theWindow,fish[i].x,fish[i].y,
            fish_width,fish_height,fishr_bits,ForeColor,BackColor,
            fishrBMask,GXcopy,AllPlanes);
}


/***********************************/
Syntax(call)
 char *call;
{
    printf ("Usage: %s [-rv] [host:display] [number of fish] \n",call);
    exit(0);
}


/***********************************/
XFishError (identifier)
       char *identifier;
{
    fprintf(stderr, "xfish: %s\n", identifier);
    exit(1);
}



/*******/
Stats()
{
    long curtime;
    float acc;

    curtime=time(0);
    acc = (float) shots  / (float) startnfish;
    XFeep(0);  XFeep(0);  XFeep(0);  XFlush();
    printf("You used %d shots to hit %d fish.  (in %d seconds)\n",
            shots,startnfish,curtime-starttime);
    printf("  For an accuracy ratio of: %f\n", acc);

    if (acc < 1.5) printf("Nice shootin', Tex!\n");
    exit(0);
}



static int timerdone;

/*******/
onalarm()
/*******/
{
  timerdone=1;
}

/*******/
Timer(val)
 long val;
/*******/
{
    /* waits 'val' microseconds */

    struct itimerval it;

    bzero(&it, sizeof(it));
    it.it_value.tv_usec = val;
    timerdone=0;
    signal(SIGALRM,onalarm);
    setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
    while (1) {
        sigblock(sigmask(SIGALRM)); /* note:  have to block, so that ALRM */
        if (timerdone) break;       /* doesn't occur between 'if (timerdone)'*/
        else sigpause(0);           /* and calling sigpause(0) */
        }
    sigblock(0);                    /* turn ALRM blocking off */
    signal(SIGALRM,SIG_DFL);
}

\Rogue\Monster\
else
  echo "will not over write ./xfish.c"
fi
echo "Finished archive 1 of 1"
exit

bradley@dsl.cis.upenn.edu (John Bradley) (10/21/87)

For the benefit of the other three or four people who've succeeded in getting
X11 up and running, here's an Exciting Application Program.  It puts fish on
the screen, then it let's you Shoot Them.  Gosh-oh-rootie, what could be more
fun?  (Well, hundreds of things, but that's not important right now.)

Anyhow, I've run it on an RT with an APA16 display.  It should probably run on
anything else, but who knows.  I'll be the first to point out that almost
certainly doesn't follow the 'correct' method of dealing with the window
manager, whatever that method happens to be This Week.  Life on the cutting 
edge, y'know?  It also runs slower than it used to (no big surprise there).
Furthermore, shooting the fish is Damned Near Impossible anymore, because for
whatever reason, it takes a good 2-3 seconds between the time you click the
mouse and the time my program notices this fact.  I'm open for suggestions
on how to speed this up.

Enjoy.

John Bradley  -  bradley@cis.upenn.edu  -  University of {ennsylvania


--------------------------(cut here)-------------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\Rogue\Monster\'
Notes on 'xfish':

Xfish is a program that opens a window that, for all intents and purposes,
appears to be the root window, except for the minor fact that there's now
fish swimming around in it.  It also has the added benefit of instantly 
raising your load average by 1 unit.  If you're doing it over a network, it
even simulates heavy network traffic.  It's the program that does it all, 
provided you define 'all' as meaning 'puts fish on the screen'.

You can specify the number of fish, from 1 to 100.  The default is 20.

If you grow bored with having fish flapping around on your desktop, you can
poke them with the left button.  This will cause the fish to feep at you, and
turn around.

If you grow tired of annoying fish, you can just blow the suckers away by 
shooting them with the right button.

Important Fish-Blastin' Tip:  You have to lead the fish, as there's a delay
between the time the mouse is clicked, and the time that the program finds
out that the mouse was clicked.  The time is fairly constant, so the faster
a fish is moving, the more you have to lead it.  Shooting the last two or
three fishes is mostly a matter of luck.  And superior firepower.

When you've blasted all the fish, it'll print give you your seconds-per-fish
ratio.  It's more fun to compete.  Play flipper skill games for fun and 
excitement.

John Bradley, 
Graphics Weenie
University of Pennsylvania

(bradley@cis.upenn.edu)

\Rogue\Monster\
else
  echo "will not over write ./README"
fi
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\Rogue\Monster\'
INCLUDES = 

XLIB = /usr/lib/libX.a
CFLAGS = $(INCLUDES)
CLIBS = 

.SUFFIXES: .o .h .c .a

OBJS = xfish.o

all: xfish

xfish: $(OBJS)
	cc $(CFLAGS) -o xfish $(OBJS) $(XLIB) $(CLIBS)

\Rogue\Monster\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./lfish`
then
echo "writing ./lfish"
cat > ./lfish << '\Rogue\Monster\'
#define lfish_width 32
#define lfish_height 16
static char lfish_bits[] = {
   0x00, 0xc0, 0x07, 0x00, 0x00, 0xb0, 0x06, 0x00, 0x80, 0x7f, 0x03, 0xe0,
   0x60, 0x82, 0x03, 0xb0, 0x18, 0x00, 0x0c, 0x68, 0x64, 0x02, 0xf0, 0x37,
   0x62, 0x00, 0x00, 0x28, 0x01, 0xaa, 0xaa, 0x36, 0x46, 0x00, 0x00, 0x28,
   0x38, 0x03, 0xc0, 0x5f, 0xb0, 0x28, 0x30, 0xb0, 0xc0, 0x39, 0x0e, 0xe0,
   0x00, 0xee, 0x01, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00,
   0x00, 0xc0, 0x00, 0x00};
\Rogue\Monster\
else
  echo "will not over write ./lfish"
fi
if `test ! -s ./lfishmask`
then
echo "writing ./lfishmask"
cat > ./lfishmask << '\Rogue\Monster\'
#define lfishmask_width 32
#define lfishmask_height 16
static char lfishmask_bits[] = {
   0x00, 0xc0, 0x07, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x80, 0xff, 0x03, 0xe0,
   0xe0, 0xff, 0x03, 0xf0, 0xf8, 0xff, 0x0f, 0x78, 0xfc, 0xff, 0xff, 0x3f,
   0xfe, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x3f,
   0xf8, 0xff, 0xff, 0x7f, 0xf0, 0xff, 0x3f, 0xf0, 0xc0, 0xff, 0x0f, 0xe0,
   0x00, 0xfe, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
   0x00, 0xc0, 0x00, 0x00};
\Rogue\Monster\
else
  echo "will not over write ./lfishmask"
fi
if `test ! -s ./rfish`
then
echo "writing ./rfish"
cat > ./rfish << '\Rogue\Monster\'
#define rfish_width 32
#define rfish_height 16
static char rfish_bits[] = {
   0x00, 0xe0, 0x03, 0x00, 0x00, 0x60, 0x0d, 0x00, 0x07, 0xc0, 0xfe, 0x01,
   0x0d, 0xc0, 0x41, 0x06, 0x12, 0x30, 0x00, 0x18, 0xec, 0x0f, 0x40, 0x26,
   0x14, 0x00, 0x00, 0x46, 0xac, 0xaa, 0x4a, 0x80, 0x14, 0x00, 0x00, 0x62,
   0xfa, 0x03, 0xc0, 0x1c, 0x0d, 0x0c, 0x14, 0x0d, 0x07, 0x70, 0x9c, 0x03,
   0x00, 0x80, 0x77, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x00,
   0x00, 0x00, 0x03, 0x00};
\Rogue\Monster\
else
  echo "will not over write ./rfish"
fi
if `test ! -s ./rfishmask`
then
echo "writing ./rfishmask"
cat > ./rfishmask << '\Rogue\Monster\'
#define rfishmask_width 32
#define rfishmask_height 16
static char rfishmask_bits[] = {
   0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x07, 0xc0, 0xff, 0x01,
   0x0f, 0xc0, 0xff, 0x07, 0x1e, 0xf0, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x3f,
   0xfc, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x1f, 0x0f, 0xfc, 0xff, 0x0f, 0x07, 0xf0, 0xff, 0x03,
   0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x07, 0x00,
   0x00, 0x00, 0x03, 0x00};
\Rogue\Monster\
else
  echo "will not over write ./rfishmask"
fi
if `test ! -s ./xfish.c`
then
echo "writing ./xfish.c"
cat > ./xfish.c << '\Rogue\Monster\'
/*
 * xfish.c  -  serves no useful purpose whatsoever
 *
 *  Author:    John H. Bradley, University of Pennsylvania
 *                (bradley@cis.upenn.edu)
 *                     October, 1987
 *
 *  For 4.2ish Unix systems running X V11R1
 */


#include <stdio.h>
#include <math.h>
#include <strings.h>
#include <signal.h>
#include <X/Xlib.h>
#include <X/Xutil.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/timeb.h>


/* handy-dandy functions */
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? -(a) : (a))


/* objects */
Display   *disp;
Window    theWindow;
Pixmap    stipP, lfishP, rfishP, lfishmaskP, rfishmaskP;
GC        gc,lgc,rgc;
XGCValues xgcv;
XSetWindowAttributes xswa;

#define root_weave_width 16
#define root_weave_height 16
static char root_weave_bits[] = {
   0x77, 0x77, 0xdd, 0xdd, 0xbb, 0xbb, 0xee, 0xee, 0x77, 0x77, 0xdd, 0xdd,
   0xbb, 0xbb, 0xee, 0xee, 0x77, 0x77, 0xdd, 0xdd, 0xbb, 0xbb, 0xee, 0xee,
   0x77, 0x77, 0xdd, 0xdd, 0xbb, 0xbb, 0xee, 0xee};

static char iroot_weave_bits[] = {
   0x88, 0x88, 0x22, 0x22, 0x44, 0x44, 0x11, 0x11, 0x88, 0x88, 0x22, 0x22,
   0x44, 0x44, 0x11, 0x11, 0x88, 0x88, 0x22, 0x22, 0x44, 0x44, 0x11, 0x11,
   0x88, 0x88, 0x22, 0x22, 0x44, 0x44, 0x11, 0x11};

#define fish_width 32
#define fish_height 16

static char lfish_bits[] = {
   0x00, 0xc0, 0x07, 0x00, 0x00, 0xb0, 0x06, 0x00, 0x80, 0x7f, 0x03, 0xe0,
   0x60, 0x82, 0x03, 0xb0, 0x18, 0x00, 0x0c, 0x68, 0x64, 0x02, 0xf0, 0x37,
   0x62, 0x00, 0x00, 0x28, 0x01, 0xaa, 0xaa, 0x36, 0x46, 0x00, 0x00, 0x28,
   0x38, 0x03, 0xc0, 0x5f, 0xb0, 0x28, 0x30, 0xb0, 0xc0, 0x39, 0x0e, 0xe0,
   0x00, 0xee, 0x01, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00,
   0x00, 0xc0, 0x00, 0x00};

static char lfishmask_bits[] = {
   0x00, 0xc0, 0x07, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x80, 0xff, 0x03, 0xe0,
   0xe0, 0xff, 0x03, 0xf0, 0xf8, 0xff, 0x0f, 0x78, 0xfc, 0xff, 0xff, 0x3f,
   0xfe, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x3f,
   0xf8, 0xff, 0xff, 0x7f, 0xf0, 0xff, 0x3f, 0xf0, 0xc0, 0xff, 0x0f, 0xe0,
   0x00, 0xfe, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
   0x00, 0xc0, 0x00, 0x00};

static char rfish_bits[] = {
   0x00, 0xe0, 0x03, 0x00, 0x00, 0x60, 0x0d, 0x00, 0x07, 0xc0, 0xfe, 0x01,
   0x0d, 0xc0, 0x41, 0x06, 0x12, 0x30, 0x00, 0x18, 0xec, 0x0f, 0x40, 0x26,
   0x14, 0x00, 0x00, 0x46, 0xac, 0xaa, 0x4a, 0x80, 0x14, 0x00, 0x00, 0x62,
   0xfa, 0x03, 0xc0, 0x1c, 0x0d, 0x0c, 0x14, 0x0d, 0x07, 0x70, 0x9c, 0x03,
   0x00, 0x80, 0x77, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x00,
   0x00, 0x00, 0x03, 0x00};

static char rfishmask_bits[] = {
   0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x07, 0xc0, 0xff, 0x01,
   0x0f, 0xc0, 0xff, 0x07, 0x1e, 0xf0, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x3f,
   0xfc, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x1f, 0x0f, 0xfc, 0xff, 0x0f, 0x07, 0xf0, 0xff, 0x03,
   0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x07, 0x00,
   0x00, 0x00, 0x03, 0x00};


#define MAXFISH 100
struct fishstr {  short x,y,dx,dy;  } fish[MAXFISH];

int NUMFISH=20, startnfish=20, shots=0;

long starttime;

/**************/
main(argc, argv)
    int   argc;
    char *argv[];
/**************/
{
    int i,dpcs,n,fcnt;
    char *strind;

    char *fc, *bc;
    char *display = NULL;

    char *def;
    short bot,right;
    XSizeHints xsh;


    /*********************Options*********************/

    for (i = 1; i < argc; i++) {

        strind = index(argv[i], ':');       /* is it display address? */
        if(strind != NULL) {
            display = argv[i];
            continue;
            }

        if (n=atoi(argv[i])) {
            if (n<1) n=1;
            if (n>100) n=100;
            NUMFISH=startnfish=n;
            continue;
            }

        Syntax(argv[0]);
    }


    /*****************************************************/

    /* Open up the display. */

    if ((disp=XOpenDisplay(display)) == NULL) {
        fprintf(stderr, "%s: Can't open display ''\n",argv[0],display);
        exit(1);
        }


    bot  =DisplayHeight(disp,DefaultScreen(disp));
    right=DisplayWidth (disp,DefaultScreen(disp));

    xsh.flags = USSize | USPosition;
    xsh.x = xsh.y = 0;
    xsh.width = right;
    xsh.height= bot;

    xswa.event_mask = ButtonPressMask;

    theWindow = XCreateWindow(disp, DefaultRootWindow(disp), 0,0,
			right,bot,0,1,InputOutput,
			DefaultVisual(disp,DefaultScreen(disp)),
			CWEventMask,&xswa);
    

    stipP=XCreateBitmapFromData(disp,theWindow,
             iroot_weave_bits, root_weave_width, root_weave_height);

    lfishP=XCreateBitmapFromData(disp,theWindow,
				lfish_bits,fish_width,fish_height);
    rfishP=XCreateBitmapFromData(disp,theWindow,
				rfish_bits,fish_width,fish_height);
    lfishmaskP=XCreateBitmapFromData(disp,theWindow,
				lfishmask_bits,fish_width,fish_height);
    rfishmaskP=XCreateBitmapFromData(disp,theWindow,
				rfishmask_bits,fish_width,fish_height);


    XSetWindowBackgroundPixmap(disp,theWindow,stipP);
    XSetNormalHints(disp,theWindow,&xsh);
    XSetStandardProperties(disp,theWindow,"fish","fish",None,0,0,&xsh);
    XMapWindow(disp,theWindow);
    XLowerWindow(disp,theWindow);

    /* init fish */
    for (i=0; i<NUMFISH; i++) {
        fish[i].x=rand()%(right-100)+50;
        fish[i].y=rand()%(bot-100)+50;
        fish[i].dx = (abs(rand()%10)+4);

        /* switch direction based on a higher-order bit.  the low-order bit
           tended to be useless */
        if (rand()&0x10) fish[i].dx = -fish[i].dx;  

        fish[i].dy=rand()%7-3;  if (fish[i].dy==0) fish[i].dy=1;
        }


    xgcv.tile=stipP;
    xgcv.graphics_exposures = False;

    gc = XCreateGC(disp,theWindow,GCTile|GCGraphicsExposures,&xgcv);
    lgc= XCreateGC(disp,theWindow,GCTile|GCGraphicsExposures,&xgcv);
    rgc= XCreateGC(disp,theWindow,GCTile|GCGraphicsExposures,&xgcv);

    xgcv.fill_style= FillTiled;

    xgcv.clip_mask = None;

    xgcv.clip_mask = lfishmaskP;
    XChangeGC(disp,lgc,GCClipMask|GCFillStyle,&xgcv);

    xgcv.clip_mask = rfishmaskP;
    XChangeGC(disp,rgc,GCClipMask|GCFillStyle,&xgcv);

    starttime=time(0);


    /**************** Main loop *****************/

    fcnt = 0;
    while (1) {
        XEvent event;
        short  x,y,bnum;

      if (XPending(disp)) {
            XNextEvent(disp,&event);
            if (event.type == ButtonPress) {
                XButtonEvent *butevent = (XButtonEvent *) &event;

                bnum = butevent->button;
                if ((bnum == Button1) || (bnum == Button3)) {

                    if (bnum == Button3) shots++;

                    x = butevent->x;  y = butevent->y;
                    for (i=0; i<NUMFISH; i++) {
                        if ( (x >= fish[i].x) &&
                             (x <= fish[i].x+fish_width) &&
                             (y >= fish[i].y) &&
                             (y <= fish[i].y+fish_height) ) break;
                        }

                    if (i!=NUMFISH) {
                        XBell(disp,25);
                        EraseFish(i);
                        if (bnum == Button1) {
                            fish[i].dx = -fish[i].dx;
                            fish[i].dy = -fish[i].dy;
                            DrawFish(i);
                            }
                        else {
                            if (NUMFISH==1) Stats();
                            bcopy(&fish[NUMFISH-1],&fish[i],
                                  sizeof(struct fishstr));
                            NUMFISH--;
                            }
                        }
                    }
                }
           }

        if (fcnt>=NUMFISH) fcnt=0;  /* since it's possible NUMFISH decreased */

        EraseFish(fcnt);

        fish[fcnt].x += fish[fcnt].dx;
        fish[fcnt].y += fish[fcnt].dy;
        if (fish[fcnt].x < -50 || fish[fcnt].x > (right+50))
            fish[fcnt].dx = -fish[fcnt].dx;
        if (fish[fcnt].y < 0 || fish[fcnt].y > (bot-16))
            fish[fcnt].dy = -fish[fcnt].dy;

        DrawFish(fcnt);

        fcnt++;
        if (fcnt>=NUMFISH) { fcnt=0; Timer(100000L); }

    }  /* end main loop */
}

/*****************/
EraseFish(i)
      int i;
{
    xgcv.clip_x_origin = fish[i].x;
    xgcv.clip_y_origin = fish[i].y;

    if (fish[i].dx<0) {
        XChangeGC(disp,lgc,GCClipXOrigin|GCClipYOrigin,&xgcv);
        XFillRectangle(disp,theWindow,lgc,
                       fish[i].x,fish[i].y,fish_width,fish_height);
        }
    else {
        XChangeGC(disp,rgc,GCClipXOrigin|GCClipYOrigin,&xgcv);
        XFillRectangle(disp,theWindow,rgc,
                       fish[i].x,fish[i].y,fish_width,fish_height);
        }
}

/*****************/
DrawFish(i)
     int i;
{
    xgcv.clip_x_origin = fish[i].x;
    xgcv.clip_y_origin = fish[i].y;

    if (fish[i].dx<0) {
        XChangeGC(disp,lgc,GCClipXOrigin|GCClipYOrigin,&xgcv);
        XCopyPlane(disp,lfishP,theWindow,lgc,0,0,fish_width,fish_height,
                    fish[i].x,fish[i].y,1);
        }
    else {
        XChangeGC(disp,rgc,GCClipXOrigin|GCClipYOrigin,&xgcv);
        XCopyPlane(disp,rfishP,theWindow,rgc,0,0,fish_width,fish_height,
                fish[i].x,fish[i].y,1);
        }
}


/***********************************/
Syntax(call)
 char *call;
{
    printf ("Usage: %s [-rv] [host:display] [number of fish] \n",call);
    exit(0);
}


/***********************************/
XFishError (identifier)
       char *identifier;
{
    fprintf(stderr, "xfish: %s\n", identifier);
    exit(1);
}



/*******/
Stats()
{
    long curtime;
    float acc;

    curtime=time(0);
    acc = (float) shots  / (float) startnfish;
    printf("\007\007\007You used %d shots to hit %d fish.  (in %d seconds)\n",
            shots,startnfish,curtime-starttime);
    printf("  For an accuracy ratio of: %f\n", acc);

    if (acc < 1.5) printf("Nice shootin', Tex!\n");
    exit(0);
}



static int timerdone;

/*******/
onalarm()
/*******/
{
  timerdone=1;
}

/*******/
Timer(val)
 long val;
/*******/
{
    /* waits 'val' microseconds */

    struct itimerval it;

    bzero(&it, sizeof(it));
    it.it_value.tv_usec = val;
    timerdone=0;
    signal(SIGALRM,onalarm);
    setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
    while (1) {
        sigblock(sigmask(SIGALRM)); /* note:  have to block, so that ALRM */
        if (timerdone) break;       /* doesn't occur between 'if (timerdone)'*/
        else sigpause(0);           /* and calling sigpause(0) */
        }
    sigblock(0);                    /* turn ALRM blocking off */
    signal(SIGALRM,SIG_DFL);
}

\Rogue\Monster\
else
  echo "will not over write ./xfish.c"
fi
echo "Finished archive 1 of 1"
exit