[alt.sources] mines game for unix-pc

tjl@ceres.UUCP (Tim J. Lipetz) (10/02/89)

Here is a port of a popular game on the Sun and Macs called
'mines'.  I have added several features including guaranteed
pathes, multiple soldiers, hand-grenades, chain-reaction
explosions and scoring.  It uses the graphics library on
the unix-pc and so is machine specific, but if anyone
wants to port these features to another machine, thats
fine with me.  Please check with the original author first
(I'm sure he wouldn't mind either, but it is still a good
idea.)  Of course, preserve all credits in the current version.

The new features allow play with a much higher density of 
mines.  My highest score in about a year of play is 1400 (grunt
level using only one hand-grenade and losing no soldiers).
Hope you enjoy it.

Timothy Lipetz
...!osu-cis!n8emr!ceres!tjl


************************************************************
: run sh on this file to unbundle
echo x - Makefile
cat >Makefile <<'!Funky!Stuff!'
#
# Makefile for Mines package.
#

include $(MAKEINC)/Makepre.h

OBJS = board.o boardsw.o main.o
SRCS = board.c boardsw.c main.c
HDRS = mines.h

#CFLAGS = -g
CFLAGS = -O

mines : $(OBJS)
	$(LD) $(SHAREDLIB) -o mines $(OBJS)

lint : $(SRCS) $(HDRS)
	lint $(SRCS)

clean : 
	/bin/rm -f *.o mines core

$(OBJS) : $(HDRS)

shar : dist.sh

dist.sh : Makefile $(HDRS) $(SRCS)
	shar Makefile README $(HDRS) $(SRCS) > dist.sh
!Funky!Stuff!
echo x - README
cat >README <<'!Funky!Stuff!'
 * Copyright (c) 1987 Tom Anderson; 20831 Frank Waters Road;
 * Stanwood, WA  98282.   All rights reserved.
 *
 * Modified for AT&T UnixPC, hand-grenades,scoring added & path guaranteed
 *			- Redistributed w/permission of original author
 *			- Timothy J. Lipetz; Worthington, OH
 *			- July 1988
 *
Here are the sources for the mines game.  I hacked this up from the chess
tool - you might recognize the lineage.  I've been too lazy to write a 
manual page for it; however, it's pretty simple:

Function Keys: Controls how many mines are hidden in the array.
To change the level, press key or pick label with mouse.
Re-picking a level will start a new game at the same level
as the previous one.  Paths are now guaranteed to exist.

The Message Line:  Tells you how many 
mines are in immediately adjacent squares (including diagonals).  The
top left four squares are always guaranteed to be free of mines.

The "minefield":  The object is to get from 
the upper left square to the lower right square without being blown up.
Click:
	- the left mouse button on any adjacent square to move there.  
	Squares that you have occupied are highlighted.

	- the middle mouse button on any square to mark the square as
	"dangerous".  Once the square is marked as dangerous, you 
	cannot accidentally move there.

	- the right mouse button on any square to mark the square as 
 	"safe".  This has no effect on your ability to move on the square,
	but eliminates the need to keep a separate piece of paper around
	or to have an excessively high IQ.

The middle and right mouse buttons are "toggles" - that is, clicking on
a square again toggles the square's designation or changes its type (i.e.,
from "safe" to "dangerous").  Both have no effect on squares you have
already occupied.

Use exit key on keyboard to end game.	- tjl

You can continue to play with extra soldiers. - tjl

Exploding mines set off chain-reaction of all (4) adjacent mines.
This continues recursively.  - tjl

Added hand-grenades.  To use: select Hand Grenade, it tells you how
many you have (Total on Label, #Left in message), pick square to
start chain reaction explosion. - tjl

The games is now guaranteed to have a path that can lead to a win
without using hand-grenades or losing soldiers.  However, it is
nearly impossible to win with more than eighty mines unless you
use hand-grenades. - tjl

(A note for people who don't understand sarcasm - Yes, the names of
 the playing levels are correct! - tjl)

 The Scoring is as follows:
		No points unless mine field crossed.
		10 pt. for each mine on original field.
		(-300) pts. for each soldier lost.
		(-100) pts. for each hand grenade used.
				    - tjl

Tom Anderson, (206) 356-5895
John Fluke Mfg. Co., Inc.,  P.O. Box C9090 M/S 245F, Everett, Wa. 98206
{ hplsla, microsoft, uw-beaver, sun, tikal }!fluke!toma

Modified by Timothy J. Lipetz 
Worthington, Ohio.
!Funky!Stuff!
echo x - mines.h
cat >mines.h <<'!Funky!Stuff!'
/*
 * mines header
 *
 * Copyright (c) 1987 Tom Anderson; 20831 Frank Waters Road;
 * Stanwood, WA  98282.   All rights reserved.
 *
 * Modified for AT&T UnixPC - Timothy J. Lipetz; Worthington, OH
 *			    - July 1988
 */

#define BOOL 			int
#ifndef TRUE
#define TRUE			1
#endif
#ifndef FALSE
#define FALSE			0
#endif

/*
 * number of board squares per side 
 */
#define	XSIDE_SIZE		22
#define	YSIDE_SIZE		14

/*
 * default number of mines
 */
#define	DEFAULT_MINE_QTY	40
#define	DEFAULT_LEVEL_STR	"Major"
#define	DEFAULT_GRENADE_QTY	3

/*
 * Connectivity defines -
 * Note: FALSE ( 0 ) is also a valid value
 */
#define LL 1
#define UR 2

/*
 * board coordinates
 */
typedef struct {
    int x;
    int y;
} Coordinate;

/*
 * square state
 */
typedef struct {
    int connected;	/* is there a chain of mines to edge? */
    BOOL traversed;	/* has the poor soul stepped here? */
    BOOL mined;		/* is this square mined? */
    BOOL occupied;	/* is this square occupied? */
    BOOL unsafe;	/* has the player determined a mine here? */
    BOOL safe;		/* has the player determined no mines here? */
    BOOL blown;		/* has the player stepped on a mine here? */
} Square;


extern void InitBoard(), DoMove(), InitBoardSW(), DrawSquare(),
    DrawBoard(), InitLevelSW(), InitMsgSW(), Message(),
    ParseToolArgs(), InitTool(), RunTool(), MarkSquare();
extern Square * GetSquare();
extern char * MineWarningMessage();
extern BOOL GameOver;
extern BOOL GrenadeNext;
extern int GrenadesLeft;
extern int SquareWidth, SquareHeight;
extern int Score, Level;
extern char * LevelStr;
!Funky!Stuff!
echo x - board.c
cat >board.c <<'!Funky!Stuff!'
/*
 * manage the board state
 *
 * Copyright (c) 1987 Tom Anderson; 20831 Frank Waters Road;
 * Stanwood, WA  98282.   All rights reserved.
 *
 * Modified for AT&T UnixPC - Timothy J. Lipetz; Worthington, OH
 *			    - July 1988
 */
static char copyright[] = "Copyright 1987 Tom Anderson";

#include <stdio.h>
#include <string.h>
#include <sys/types.h>

#include "mines.h"

Square MainBoard[XSIDE_SIZE][YSIDE_SIZE];
Coordinate PlayerLocation;
BOOL GameOver;
BOOL GrenadeNext;
int Score;	/* how many men lost */
BOOL BlewUpSelf;

/*
 * set up the playing surface at the beginning of the game
 */
void
InitBoard()
{
    register int i, j, minesPlaced, ran;
    register Square * sqp;
    BOOL connected;
    /*
     *	Keep list of available spaces - swap used ones out
     */
    int unmined[ (XSIDE_SIZE * YSIDE_SIZE) ];	/* available spaces */
    int unminedcnt = (XSIDE_SIZE * YSIDE_SIZE);
    /* swap used ones out as follows */
    /* #define UNMSWAP(a) {unmined[a]=unmined[--unminedcnt];} */

    /* 
     * set up unmined list  (free list of spaces)
     */
    for (i = 0 ; i < unminedcnt; i++)
    {
	unmined[i] = i;
    }
    /* decrement to disallow last space */
    unminedcnt--;
    /* disallow beginning 4 spaces */
    unmined[0]=unmined[--unminedcnt];
    unmined[1]=unmined[--unminedcnt];
    unmined[XSIDE_SIZE]=unmined[--unminedcnt];		/* X side */
    unmined[XSIDE_SIZE+1]=unmined[--unminedcnt];

    /*
     * zero the board 
     */
    for (i = 0 ; i < XSIDE_SIZE ; i++) {
	for (j = 0 ; j < YSIDE_SIZE ; j++) {
	    sqp = &MainBoard[i][j];
	    sqp->traversed = sqp->mined = sqp->occupied = sqp->unsafe
		      = sqp->safe = sqp->connected = sqp->blown = FALSE;
	}
    }
    Score = 0;

    /*
     * I completely rewrote the random placing algorithm here - T. Lipetz
     * 		The original generated >750 random numbers (3 board passes
     *		plus re-tries).  This version requires 'Level' random nums
     *		(~20-80) with no retries (I keep list of available spaces).
     *
     * I also added a test to prevent impossible mine fields which the
     * 		original did generate.			- T. Lipetz 7/88
     *		This does reject placing mines in some cells but never
     *		retries the same cell,  thus the worst case would be
     *		trying each cell once, and that only occurs in the most
     *		extreme cases (only with almost all mines) ! - tjl)
     */
    /* Although this loop might quit before all mines are placed, this
     * can only happen after all available places are rejected.  Thus
     * only when the field is almost saturated with mines.  (It
     * happens about half the time when placing 230 mines in 256 cells,
     * and about 1/20th the time when placing 220 in 256.) Since
     * we usually place much fewer mines, it virtually never
     * fails to place them all  - tjl
     */
    for (minesPlaced = 0 ; (minesPlaced<Level) && (unminedcnt>0);   )
    {
	ran = rand() % unminedcnt;
	i = unmined[ran] % XSIDE_SIZE; /* x value */
	j = unmined[ran] / XSIDE_SIZE; /* y value */
	/* Test if blocks all paths - if not then mine it - tjl */
	if (mineplaced(i,j))
	{
	    minesPlaced++;
	}
	/* remove from available list - whether mined or not */
	unmined[ran]=unmined[--unminedcnt];
    }
    PlayerLocation.x = PlayerLocation.y = 0;
    MainBoard[0][0].occupied = MainBoard[0][0].traversed = TRUE;
    GameOver = FALSE;
    GrenadeNext = FALSE;
}

/*
 * test whether adding a mine here will block all available paths
 * -  if not, place it and record it in connected member of board cell
 * - tjl
 */
int
mineplaced(x,y)
    int x, y;
{
   /*
    * The IDEA -
    *   There is an 8-connected walkable path
    *   UNLESS there is a 4-connected trail of mines between the
    *   (upper and right) edge and the (lower and left) edge
    * The ALGORITHM -
    *	Mines placed on an edge (LL or UR) are marked as such.
    *   Mines placed next (4-connected) to one of (LL,UR) get that marking
    *      and pass it recursively to unmarked mines that are 4-connected
    *   Mines are NOT placed next to both a LL and a UR
    * This is a variation on Kruskal's algorithm for connected paths,
    * only here the only connected_sets I am interested in are LL and UR,
    * all others are not combined into a set until I need them.
    * - Timothy Lipetz	-  July 1988
    */

    int u,d,l,r;	/* up down left right cells */
    int llfound, urfound;

    u = getconnect(x,y-1);
    d = getconnect(x,y+1);
    l = getconnect(x-1,y);
    r = getconnect(x+1,y);
    llfound = ((u==LL)||(d==LL)||(l==LL)||(r==LL)||(x==0)||(y==YSIDE_SIZE-1));
    urfound = ((u==UR)||(d==UR)||(l==UR)||(r==UR)||(y==0)||(x==XSIDE_SIZE-1) );
    if(llfound && urfound)
	return(FALSE);
    MainBoard[x][y].mined = TRUE;
    if (llfound)
    {
        spreadconnection(x,y,LL); 
    }
    if (urfound)
    {
        spreadconnection(x,y,UR); 
    }
    /* else leave connected == FALSE */
    return(TRUE);
}

/*
 * Blow up square and adjacents
 * - tjl
 */
int
BlowUp(x, y)	/* Recursive thru connected MINES */
    int x, y;
{
    Square *sqp;
    int i, j;
    char str[80];
    Coordinate dest;

    sqp = &MainBoard[x][y];
    if(   (x < 0)				/* outside board */
       || (y < 0)
       || (x >= XSIDE_SIZE)
       || (y >= YSIDE_SIZE)
       || ((sqp->mined==FALSE)&&(sqp->occupied==FALSE))) 	
    {
	return;
    }
    dest.x = x;
    dest.y = y;
    
    if(sqp->occupied==TRUE)
    {
	sqp->blown = TRUE;
	sqp->occupied = FALSE;
	Score++;
	DrawSquare(&dest);
	MainBoard[0][0].occupied = TRUE;
	PlayerLocation.x = PlayerLocation.y = 0;
	DrawSquare(PlayerLocation);
	BlewUpSelf = TRUE;
	return;
    }
    /*     else */
    /* 	Flicker bomb */
    Message("  -*-*-**** KAAABBOOOOOOOMM!!! ****-*-  ");
    for(i=0; i<3; i++)
    {
	sqp->unsafe = FALSE;
	DrawSquare(&dest);
/* 	    timing loop */
	for(j=0; j<4000; j++)
	    ;
	sqp->occupied = FALSE;
	sqp->unsafe = TRUE;
	DrawSquare(&dest);
/* 	    timing loop */
	for(j=0; j<4000; j++)
	    ;
    }
    sqp->mined = FALSE;
    sqp->unsafe = FALSE;
    sqp->occupied = FALSE;
    DrawSquare(&dest);

    BlowUp(x, y+1);
    BlowUp(x, y-1);
    BlowUp(x+1, y);
    BlowUp(x-1, y);
}


/*
 * Passes connected state of cell to all adjacent unconnected mines
 * - tjl
 */
int
spreadconnection(x, y, con)	/* Recursive thru unconnected MINES */
    int x, y, con;
{
    if(   (x < 0)				/* outside board */
       || (y < 0)
       || (x >= XSIDE_SIZE)
       || (y >= YSIDE_SIZE)
       || (MainBoard[x][y].mined == FALSE)	/* no mines */
       || (MainBoard[x][y].connected != FALSE))/* mine already connected*/
    {
	return;
    }
    MainBoard[x][y].connected = con;
    spreadconnection(x, y+1, con);
    spreadconnection(x, y-1, con);
    spreadconnection(x+1, y, con);
    spreadconnection(x-1, y, con);
}

/*
 * get connected state of cell at x,y
 * RETURN (-1) if the cell is off the board
 * RETURN FALSE if cell unmined, or if cell mined but unconnected 
 * - tjl
 */
getconnect(x,y)
    int x, y;
{
    if(   (x < 0)
       || (y < 0)
       || (x >= XSIDE_SIZE)
       || (y >= YSIDE_SIZE))
    {
	return(-1);
    }
    if(MainBoard[x][y].mined == FALSE)
    {
	return(FALSE);
    }
    return(MainBoard[x][y].connected);
}

/*
 * describe the state of the board square at x, y
 */
Square *
GetSquare(bloc)
    Coordinate * bloc;
{
    return (&MainBoard[bloc->x][bloc->y]);
}

/*
 * toggle a square's marking as being probably safe or unsafe
 */
void
MarkSquare(suspect, safe)
    Coordinate * suspect;
    BOOL safe;
{
    register Square * sqp = &MainBoard[suspect->x][suspect->y];

    if (sqp->traversed)
	return;
    if (safe) {
	sqp->safe = ! sqp->safe;
	sqp->unsafe = FALSE;
    } else {
	sqp->unsafe = ! sqp->unsafe;
	sqp->safe = FALSE;
    }
    DrawSquare(suspect);
}


/*
 * try to move to a certain board coordinate
 */
void 
DoMove(dest)
    Coordinate *dest;
{
    register int y, x;
    register Square * sqp;
    int i, j;
    char str[80];

    if(GrenadeNext==TRUE)
    {
	GrenadeNext = FALSE;
	BlewUpSelf = FALSE;
	BlowUp(dest->x, dest->y);
	if(BlewUpSelf == TRUE)
	{
	    sprintf(str,"You stood too close.  Try again with %s #%d",
			    LevelStr, Score+1);
	    Message(str);
	}
	else
	{
	    Message(" ");
	}
	return;
    }
    /* else */
    /* try to move grunt */
    /*
     * if not adjacent to or equal to our current position
     * or the destination has been marked unsafe, ignore the move 
     * OR if mine is blown - tjl
     */
    sqp = &MainBoard[dest->x][dest->y];
    if (((abs(dest->x - (x = PlayerLocation.x)) > 1)&&( ! sqp->traversed))
    || ((abs(dest->y - (y = PlayerLocation.y)) > 1)&&( ! sqp->traversed))
    || (dest->x == PlayerLocation.x && dest->y == PlayerLocation.y)
    || MainBoard[dest->x][dest->y].blown
    || MainBoard[dest->x][dest->y].unsafe)
	return;
    /*
     * step off our current square
     */
    MainBoard[x][y].occupied = FALSE;
    DrawSquare(&PlayerLocation);
    /*
     * if he stepped on a mine, blow him up
     */
    if (sqp->mined)
    {
/* 	Flicker bomb and person */
	Message("  -*-*-**** KAAABBOOOOOOOMM!!! ****-*-  ");
	for(i=0; i<8; i++)
	{
	    sqp->occupied = TRUE;
	    sqp->unsafe = FALSE;
	    DrawSquare(dest);
/* 	    timing loop */
	    for(j=0; j<10000; j++)
		;
	    sqp->occupied = FALSE;
	    sqp->unsafe = TRUE;
	    DrawSquare(dest);
/* 	    timing loop */
	    for(j=0; j<10000; j++)
		;
	}
	sqp->blown = TRUE;
	sqp->unsafe = FALSE;
	sqp->occupied = FALSE;
	DrawSquare(dest);
	Score++;
	BlowUp(dest->x, dest->y);
	sprintf(str,"You just exploded.  Try again with %s #%d",
			LevelStr, Score+1);
	Message(str);
	MainBoard[0][0].occupied = TRUE;
	PlayerLocation.x = PlayerLocation.y = 0;
	DrawSquare(PlayerLocation);
    }
    /*
     * else if this is home, render congratulations
     */
    else if (dest->x == XSIDE_SIZE-1 && dest->y == YSIDE_SIZE-1)
    {
	if(GameOver)
	    return;
	PlayerLocation = * dest;
	sqp->traversed = sqp->occupied = TRUE;
	GameOver = TRUE;
	if(Score==0)
	{
	    sprintf(str, "The General is cheered.  He lost no %ss!       %d pts.", LevelStr, getfinalscore());
	}
	else if(Score==1)
	{
	    sprintf(str, "The General is cheered.  He lost only one %s!       %d pts.", LevelStr, getfinalscore());
	}
	else
	{
	    sprintf(str, "The General is cheered.  He lost only %d %ss!       %d pts.", Score, LevelStr, getfinalscore());
	}
	Message(str);
	ResetSafe();
	DrawBoard();
	recordscore(Score);
    }
    /*
     * else move onto the new square
     */
    else
    {
	PlayerLocation = * dest;
	sqp->traversed = sqp->occupied = TRUE;
	DrawSquare(dest);
	Message(MineWarningMessage());
    }
}

/*
 * Cleanup safe/unsafe stuff at gameover
 */
int
ResetSafe()
{
    register int i, j;
    register Square * sqp;
    /*
     * remove all save/unsafe marks
     */
    for (i = 0 ; i < XSIDE_SIZE ; i++)
    {
	for (j = 0 ; j < YSIDE_SIZE ; j++)
	{
	    sqp = &MainBoard[i][j];
	    sqp->safe = FALSE;
	    if(sqp->mined)
		sqp->unsafe = TRUE;
	    else
		sqp->unsafe = FALSE;
	}
    }
}

/*
 * return a pointer to the warning message
 */
char *
MineWarningMessage()
{
    static char warning[128];
    register int x, y;
    int minesFound;

    minesFound = 0;
    for (x = PlayerLocation.x - 1 ; x <= PlayerLocation.x + 1 ; x++) {
	for (y = PlayerLocation.y - 1 ; y <= PlayerLocation.y + 1 ; y++) {
	    if (x >= 0 && x < XSIDE_SIZE && y >= 0 && y < YSIDE_SIZE && MainBoard[x][y].mined)
		if( ! MainBoard[x][y].blown )
		    minesFound++;
	}
    }
    sprintf(warning, "%d mine(s) nearby", minesFound);
    return(warning);
}


int
getfinalscore()
{
    /* Score is #mines less penalty for soldiers lost and
     *    for grenades used */
    return(   (10*Level)
	    - (300*Score)
	    - (100*(DEFAULT_GRENADE_QTY-GrenadesLeft))  );
}


int
recordscore(scor)
    int scor;
{
    return;
}

!Funky!Stuff!
echo x - boardsw.c
cat >boardsw.c <<'!Funky!Stuff!'
/*
 * handle the board subwindow 
 *
 * Copyright (c) 1987 Tom Anderson; 20831 Frank Waters Road;
 * Stanwood, WA  98282.   All rights reserved.
 *
 * Modified for AT&T UnixPC - Timothy J. Lipetz; Worthington, OH
 *			    - July 1988
 */
static char copyright[] = "Copyright 1987 Tom Anderson";

#include <stdio.h>
/* #include <sys/resource.h> */
#include <sys/ioctl.h>
#include <sys/mouse.h>
#include <string.h>
#include <tam.h>
#include "mines.h"

#define XOFFSET 8
#define YOFFSET 2

/*   Blank */
/*  array blkicon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short blkicon[40] = {	  
	0xffff,	0xffff,	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	
	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	
	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	
	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	
	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	0xffff,	0xffff 	
	 };
/*   Gray */
/*  array gryicon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short gryicon[40] = {	  
	0xffff,	0xffff,	0xaaab,	0xaaaa,	0x5555,	0xd555,	0xaaab,	0xaaaa,	
	0x5555,	0xd555,	0xaaab,	0xaaaa,	0x5555,	0xd555,	0xaaab,	0xaaaa,	
	0x5555,	0xd555,	0xaaab,	0xaaaa,	0x5555,	0xd555,	0xaaab,	0xaaaa,	
	0x5555,	0xd555,	0xaaab,	0xaaaa,	0x5555,	0xd555,	0xaaab,	0xaaaa,	
	0x5555,	0xd555,	0xaaab,	0xaaaa,	0x5555,	0xd555,	0xffff,	0xffff 	
	 };
/*   Solid */
/*  array solicon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short solicon[40] = {	  
	0xffff,	0xffff,	0x0001,	0x8000,	0xfffd,	0xbfff,	0xfffd,	0xbfff,	
	0xfffd,	0xbfff,	0xfffd,	0xbfff,	0xfffd,	0xbfff,	0xfffd,	0xbfff,	
	0xfffd,	0xbfff,	0xfffd,	0xbfff,	0xfffd,	0xbfff,	0xfffd,	0xbfff,	
	0xfffd,	0xbfff,	0xfffd,	0xbfff,	0xfffd,	0xbfff,	0xfffd,	0xbfff,	
	0xfffd,	0xbfff,	0xfffd,	0xbfff,	0x0001,	0x8000,	0xffff,	0xffff 	
	 };
/*   Bomb */
/*  array bombicon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short bombicon[40] = {	  
	0xffff,	0xffff,	0x0881,	0x8000,	0x0489,	0x8000,	0x0011,	0x8000,	
	0x0001,	0x8000,	0x0e0d,	0x8000,	0x3801,	0x80fc,	0xe021,	0x87ff,	
	0xc091,	0x8fff,	0xe081,	0x9fff,	0xf001,	0xbfff,	0xf001,	0xb7ff,	
	0xf001,	0xb7ff,	0xf001,	0xb3ff,	0xe001,	0x98ff,	0xc001,	0x8e1f,	
	0x8001,	0x87ff,	0x0001,	0x80fc,	0x0001,	0x8000,	0xffff,	0xffff 	
	 };
/*   Person */
/*  array pericon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short pericon[40] = {	  
	0xffff,	0xffff,	0x0001,	0x8000,	0xc001,	0x8003,	0x6001,	0x8006,	
	0x6001,	0x8006,	0x6001,	0x8006,	0xc001,	0x8003,	0x8001,	0x8001,	
	0xf001,	0x800f,	0x9c01,	0x8039,	0x8601,	0x8061,	0x8001,	0x8001,	
	0xc001,	0x8003,	0xe001,	0x8007,	0x3001,	0x800c,	0x1801,	0x8018,	
	0x0c01,	0x8030,	0x0781,	0x81e0,	0x0001,	0x8000,	0xffff,	0xffff 	
	 };
/*   OK */
/*  array okicon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short okicon[40] = {	  
	0xffff,	0xffff,	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	
	0x0001,	0x8000,	0x0001,	0x8006,	0x0001,	0x8006,	0x0001,	0x8186,	
	0x0f81,	0x80c6,	0x18c1,	0x8066,	0x3061,	0x8036,	0x3061,	0x803e,	
	0x3061,	0x806e,	0x3061,	0x80c6,	0x18c1,	0x8186,	0x0f81,	0x8306,	
	0x0001,	0x8000,	0x0001,	0x8000,	0x0001,	0x8000,	0xffff,	0xffff 	
	 };
/* RIP icon */
/*  array ripicon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short ripicon[40] = {	  
	0xffff,	0xffff,	0x0001,	0x8000,	0x0001,	0x8000,	0xfc01,	0x801f,	
	0x0601,	0x806c,	0x0101,	0x8090,	0x0081,	0x8120,	0x0041,	0x8240,	
	0x4f41,	0x825e,	0x4921,	0x8492,	0x4f21,	0x849e,	0x4521,	0x8482,	
	0x4921,	0x8482,	0x4921,	0x8482,	0x0021,	0x8480,	0x10a9,	0xa488,	
	0x94a5,	0x94a4,	0x2525,	0x9295,	0x2505,	0x9215,	0xffff,	0xffff 	
	 };
/* General icon */
/*  array genicon contains a picture 32 pixels wide and 20 pixels high.
    for wrastop calls use srcwidth = 4, width = 32, and height = 20.  */
static unsigned short genicon[40] = {	  
	0xffff,	0xffff,	0x0401,	0x8010,	0x0201,	0x8020,	0x5201,	0x8025,	
	0x0201,	0x8020,	0xff01,	0x807f,	0x0401,	0x8010,	0x0401,	0x8010,	
	0x0401,	0x8010,	0x0801,	0x8008,	0x1001,	0x8004,	0xe001,	0x8003,	
	0xfff9,	0x9fff,	0xfca9,	0x953f,	0xfea9,	0x956a,	0xfe01,	0x807f,	
	0xfe01,	0x806a,	0xfe01,	0x806a,	0xfe01,	0x807f,	0xffff,	0xffff 	
	 };

/* square sizes */
int SquareWidth = 32, SquareHeight = 20, srcwidth = 4;
/* window pointer on 7300 */
int wn;	
/* What level of play */
int Level = DEFAULT_MINE_QTY;
char * LevelStr = DEFAULT_LEVEL_STR;

int GrenadesLeft;
int savekey;

/*
 * map a mouse coordinate to a board coordinate
 */
void
mapMouseToBoard(mlocp, blocp)
    Coordinate * mlocp;
    Coordinate * blocp;
{
    blocp->x = (mlocp->x - XOFFSET) / SquareWidth;
    blocp->y = (mlocp->y - YOFFSET) / SquareHeight;
}

/* 
 * map a board coordinate to a mouse coordinate
 */
void
mapBoardToMouse(blocp, mlocp)
    Coordinate * blocp;
    Coordinate * mlocp;
{
    mlocp->x = blocp->x * SquareWidth + XOFFSET;
    mlocp->y = blocp->y * SquareHeight + YOFFSET;
}

/*
 * initialize the board subwindow
 */
void
InitBoardSW()
{
	struct umdata um;
	int i;
	struct uwdata uw;

	/*  Make sure we're on a bitmap display!  */
	if ( ioctl(1,WIOCGETD, &uw) != 0 ) {
		fprintf(2,"You must run mines on a bitmap display\n");
		exit(1);
	}
	/*  Dump stdin, stdout, stderr, open a new window, dup to all three.  */
	close(0);
	close(1);
	close(2);
	wn = open("/dev/window",2);
	dup(wn);			/* dup to 1 */
	dup(wn);			/* dup to 2 */
	winit();
	keypad(0,1);
	wn=wcreate(1,0,25,80,0x1);
	wselect(wn);
	wputs(wn,"[2J[=1C");
/* 	wlabel(wn,"Mines"); */
	wuser(wn,"Mines");
	wprompt(wn,"Choose a level of Play from the function keys .....");
	um.um_flags = MSDOWN;
	um.um_x = 0;
	um.um_y = 0;
	um.um_w = 1;
	um.um_h = 1;
	wsetmouse (wn, &um);
	
	GrenadesLeft = DEFAULT_GRENADE_QTY;
	Level = ShowFKeys(F1);
}

int
ShowFKeys(ckey)
    int ckey;	/* which one chosen */
{
    int lev = 0;
    char s1[100];
    char s2[100];
    char c1 = ' ';
    char c2 = ' ';
    char c3 = ' ';
    char c4 = ' ';
    char c5 = ' ';
    char c6 = ' ';
/*     char c7 = ' '; */

    switch(ckey)
    {
    case F1:
	c1 = '*';
	lev = 40;
	LevelStr = "Major";
	break;
    case F2:
	c2 = '*';
	lev = 60;
	LevelStr = "Captain";
	break;
    case F3:
	c3 = '*';
	lev = 80;
	LevelStr = "Lieutenant";
	break;
    case F4:
	c4 = '*';
	lev = 100;
	LevelStr = "Sergeant";
	break;
    case F5:
	c5 = '*';
	lev = 120;
	LevelStr = "Corporal";
	break;
    case F6:
	c6 = '*';
	lev = 150;
	LevelStr = "Grunt";
	break;
    default:
	break;
    }
    sprintf(s1," %s %s %s    %s %s    %s  %d%s %s ",
		    " Major  ",
		    "Captain ",
		    "L'tenant",
		    "Sergeant",
		    "Corporal",
		    " Grunt  ",
		    GrenadesLeft, " Hand ",
		    " Reveal ");
    sprintf(s2," %s%c  %s%c  %s%c     %s%c  %s%c     %s%c  %s %s   ",
		    "  (40)", c1,
		    "  (60)", c2,
		    "  (80)", c3,
		    " (100)", c4,
		    " (120)", c5,
		    " (150)", c6,
		    "Grenades",
		    "  Map ");

    wslk(wn, 0, s1, s2, 0);
    Message("");
    return(lev);
}

/*
 * draw a square
 */
void
DrawSquare(bloc)
    Coordinate * bloc;
{
    Coordinate mloc;
    unsigned short * pr;
    Square * sqp = GetSquare(bloc);

    /* determine which pixrect to paint the square with */
    if (sqp->blown)
	pr = ripicon;
    else if ( GameOver && sqp->occupied)
	pr = genicon;
    else if ( sqp->occupied)
	pr = pericon;
    else if (sqp->traversed)
	pr = gryicon;
    else if ( ! GameOver && sqp->unsafe || GameOver && sqp->mined)
	pr = bombicon;
    else if ( ! GameOver && sqp->safe)
	pr = okicon;
    else 
	pr = blkicon;
    /* paint the square */
    mapBoardToMouse(bloc, &mloc);
    wrastop(wn,pr,srcwidth,0,0,0,0, mloc.x, mloc.y,
			SquareWidth, SquareHeight,SRCSRC,DSTSRC,0);
}

/*
 * draw the playing surface and victim area
 */
void
DrawBoard()
{
    Coordinate bloc;

    /* draw the playing area */
    for (bloc.x = 0 ; bloc.x < XSIDE_SIZE ; bloc.x++) {
	for (bloc.y = 0 ; bloc.y < YSIDE_SIZE ; bloc.y++) {
	    DrawSquare(&bloc);
	}
    }
}

void 
Message(cp)
    char * cp;
{
    wprompt(wn, cp);
}


void
RunMainLoop()
{
    int key;
    int mousex, mousey, mouseb, mouser;
    int mouse;
    Coordinate mloc;
    Coordinate bloc;
    char str[100];

    while (1)
    {
	key = wgetc(wn);
	switch(key)
	{
	case Mouse:
	    wreadmouse(wn,&mousex,&mousey,&mouseb,&mouser);
	    mloc.x = mousex;
	    mloc.y = mousey;
	    mapMouseToBoard(&mloc, &bloc);
	    if ( (bloc.x >= XSIDE_SIZE)
	       ||(bloc.y >= YSIDE_SIZE)
	       ||(bloc.x < 0)
	       ||(bloc.y < 0) )
	    {
		break;
	    }
	    if(mouseb & MBUTL)
	    {
		DoMove(&bloc);
	    }
	    else if(mouseb & MBUTM)
	    {
		/*
		 * else if he is toggling a square's unsafe marking 
		 */
		MarkSquare(&bloc, FALSE);
	    }
	    else if(mouseb & MBUTR)
	    {
		/*
		 * else if he is toggling a square's safe marking 
		 */
		MarkSquare(&bloc, TRUE);
	    }
	    break;
	case F1:
	case F2:
	case F3:
	case F4:
	case F5:
	case F6:
	    GrenadesLeft = 3;
	    Level = ShowFKeys(key);
	    savekey = key;
	    InitBoard();
	    DrawBoard();
	    break;
	case F7:
	    if(GrenadesLeft > 0)
	    {
		GrenadeNext = TRUE;
		GrenadesLeft--;
	        (void)ShowFKeys(savekey);
		Message("Ready to throw Hand Grenade.");
	    }
	    else
	    {
		Message("No more Grenades left.");
	    }
	    break;
	case F8:
	    if(GameOver == TRUE)
		break;
	    GameOver = TRUE;
	    if(Score==0)
	    {
		sprintf(str, "The General yells, 'You quit with no %ss lost!' - 0 pts.", LevelStr);
	    }
	    else if(Score==1)
	    {
		sprintf(str, "The General yells, 'You quit with only one %s lost!' - 0 pts.", LevelStr);
	    }
	    else
	    {
		sprintf(str, "The General yells, 'You quit with only %d %ss lost!' - 0 pts.", Score, LevelStr);
	    }
	    Message(str);
	    ResetSafe();
	    DrawBoard();
	    break;
	case Exit:
	    exit(0);
	default:
	    break;
	}
    }
}
!Funky!Stuff!
echo x - main.c
cat >main.c <<'!Funky!Stuff!'
/*
 * main part of the mines program
 *
 * Copyright (c) 1987 Tom Anderson; 20831 Frank Waters Road;
 * Stanwood, WA  98282.   All rights reserved.
 *
 * Modified for AT&T UnixPC - Timothy J. Lipetz; Worthington, OH
 *  & path guaranteed & scoring added
 *			    - July 1988
 */
static char copyright[] = "Copyright 1987 Tom Anderson";

#include <stdio.h>
#include <string.h>
#include <pwd.h>

#include "mines.h"

main(argc, argv)
    int argc;
    char ** argv;
{
    register int i, j;
    char * cp;

    /* randomize things a bit */
    (void) srand((unsigned) getpid());
    /* initialize the board state */
    InitBoard(DEFAULT_MINE_QTY);
    InitBoardSW();
    DrawBoard();
    /* now play the game */
    RunMainLoop();
}
!Funky!Stuff!
: End of shell archive