[comp.sources.games] v05i073: wanderer2 - mini rogue-like adventure game

games@tekred.TEK.COM (10/18/88)

Submitted by: Steven Shipway <csupt@cu.warwick.ac.uk>
Comp.sources.games: Volume 5, Issue 73
Archive-name: wanderer2/Part01

	[This is the latest version of wanderer, the original of which was
	 posted in vol5, issues 2 & 3. See the note below from the author
	 for what's changed.   -br]

[[  Here it is, the long awaited sequel - WANDERER Version 2, with builtin
MSDOS port! This can be compiled on most UNIX systems, and also (thanks to
Greg Margo) on PC's. It is much better than the original Wanderer, and has
a builtin editor as well as having the develop and edithiscore programs
built into it. There are also several new screens, a credits file, a
disable passwords option, a large playing area, a save/restore game
facility, ....

-Steven Shipway
csupt@uk.ac.warwick.cu  (from outside the UK: csupt@cu.warwick.ac.uk)
...!uunet!mcvax!ukc!warwick!{maujp,csupt} ]]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  README MANIFEST edit.c fall.c game.c jump.c read.c
#   scores.c screens screens/no_pws wand_head.h
# Wrapped by billr@saab on Mon Oct 17 11:23:30 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4011 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X                        * W A N D E R E R *
X                ----------------------------------
X
X    This program requires the header files string.h and curses.h, and
Xthe curses and termcap libraries libcurses.a and libtermcap.a. If your
Xsystem doesnt have them then you might as well give up now.
X
X    Still here? Good - then everythings OK.
X
X    First thing to do is edit the wand_head.h file. Most of the filenames
Xare self-explanatory - the lock file is usually in /tmp , you probably
Xdont need to change it. SCREENPATH is the directory in which the screen
Xfiles, screen.* , are kept. HISCOREPATH is the name of the hiscore table
Xfile - this will be created when you run the program, but must have group
Xand other read and write permission. Also, the directory SCREENPATH is used
Xto hold the credits file.
X    The masterpassword is the password that you can give when you try to
Xjump screen with ~ (see file wand.info) that will allow you to go to any
Xscreen at will. This is for wanderer 'wizards' only. Separate passwords
Xfor each screen are drawn from the file /usr/dict/words - if you dont have
Xit on your system then you'll have to change the file jump.c . These passwords
Xare given to the player upon completing each screen. The passwords can be
Xdisabled by creating a file in the SCREENPATH directory called no_pws .
X
X    New screens can be created by using the editor (thanx play@nl.cwi) that
Xis built into the game. You enter it with the -e flag, and the screen you edit
Xis held in the file ./screen . To add this one to the others, place it in the
XSCREENPATH directory with a name of the form screen.* , making sure that it is
Xreadable by everyone and that the screens number is subsequent to the last of
Xthe screens already held in the directory. Screens may be tested with
Xeither 'p' or 'n', and by using 'm' the number of moves for the screen may be
Xaltered.
X
X    The hiscore table holds only one entry per username - this is to
Xprevent one or two people from taking over the entire table.  If you object to
Xthis feature, it is easily removed from the scores.c file. The table can also
Xbe edited by the 'wizard' using the -m flag. This prompts for the
Xmasterpassword before allowing you to remove any entry by typing its
Xnumber. Use '0' to exit the editor.
X
X    Not much more to say, really. Info on playing the game can be found in
Xthe wand.info file. Once you have edited the header file, just type 'make'
Xto run the makefile. You may need to edit the makefile so that it conforms
Xwith your system. If you dont know how to do this, there's bound to be
Xsomeone around who does.
X
X    Environment variables:
X        Wanderer uses several of these. Here they are...
XSAVEFILE ---- the path of the file to be used for saved games
XNEWKEYS  ---- if you want to redefine the keys
XNEWNAME, NAME, USER ---- scanned in that order to get a name for the hiscore
X                         table.
X
X    The MSDOS port and save routines are courtesy of Greg Margo, who has also
Xtidied up a lot of my messy programming :-). Any problems with them, send
Xto HIM, since I wont know what to do.
X
X    All that remains is for me to say that the source was written by me,
XSteven Shipway,  on a sun/3-160 called poppy at Warwick University. The
Xlatter are completely unaware of this major breakthrough in software
Xdesign (:-), and this is probably a good idea, since they may well disapprove
Xof this use of computing time and facilities! (Only kidding)
X
X                                -Steven Shipway
X
X------------------------------------------------------------------------------
XSummary of flags:
X
X-c  Reads credits file from SCREENPATH/credits
X-s  Shows hiscore table from HISCOREPATH
X-e  Enters screen editor working on file ./screen
X-m  Enters hiscore table editor after prompting for the MASTERPASSWORD
X-f  Starts game with map-type screen instead of normal screen - although I
X        personally think this makes the game too easy...
X------------------------------------------------------------------------------
END_OF_FILE
if test 4011 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1385 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X Makefile                   2	
X Makefile.msdos             2	
X README                     1	
X display.c                  2	
X edit.c                     1	
X fall.c                     1	
X game.c                     1	
X help.c                     2	
X icon.c                     2	
X jump.c                     1	
X m.c                        2	
X read.c                     1	
X save.c                     2	
X scores.c                   1	
X screens                    1	
X screens/README             2	
X screens/credits            2	
X screens/no_pws             1	
X screens/screen.1           2	
X screens/screen.10          2	
X screens/screen.11          2	
X screens/screen.12          2	
X screens/screen.13          2	
X screens/screen.14          2	
X screens/screen.15          2	
X screens/screen.16          2	
X screens/screen.17          2	
X screens/screen.18          2	
X screens/screen.19          2	
X screens/screen.2           2	
X screens/screen.20          2	
X screens/screen.3           2	
X screens/screen.4           2	
X screens/screen.5           2	
X screens/screen.6           2	
X screens/screen.7           2	
X screens/screen.8           2	
X screens/screen.9           2	
X screens/screen.ken         2	
X wand_head.h                1	
END_OF_FILE
if test 1385 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'edit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'edit.c'\"
else
echo shar: Extracting \"'edit.c'\" \(3942 characters\)
sed "s/^X//" >'edit.c' <<'END_OF_FILE'
X#include "wand_head.h"
X
Xextern char *playscreen();
X
Xextern int debug_disp;
Xextern char screen[NOOFROWS][ROWLEN+1];
X
X/* Print instructions around the screen */
Xvoid instruct()
X{
Xstatic char *inst[] = { "O   Boulder",
X			"< > Arrows",
X			":   Earth",
X			"!   Landmine",
X			"*   Treasure",
X			"/ \\ Deflectors",
X			"+   Cage",
X			"= # Rock",
X			"T   Teleport (1 max)",
X			"A   Arrival (1 max)",
X			"X   Exit (always 1)",
X			"@   Start (always 1)",
X			"M   Big Monster (1 max)",
X			"S   Baby Monster",
X			"-   Alternative space",
X			"C   Time Capsule" };
Xint loop;
Xfor(loop = 1;loop < 17; loop++)
X    {
X    move(loop,55);
X    addstr(inst[loop-1]);
X    }
Xmove(21,0);
Xaddstr("Use wanderer keys to move. q = quit, p/n = play, m = change no. of moves.");
X}
X
Xvoid noins()
X{
Xint loop;
Xfor(loop =1;loop < 17; loop++)
X    {
X    move(loop,55);
X    addstr("                       ");
X    }
Xmove(21,0);
Xaddstr("                                                                            ");
X}
X
X/* Actual edit function */
X
Xvoid editscreen(num,score,bell,maxmoves,keys)
Xint  num, maxmoves,
X     *bell,
X     *score;
Xchar keys[10];
X{
Xint  x,y,sx=0,sy=0,quit=0,nx,ny;
Xchar (*frow)[ROWLEN+1] = screen,
X     ch;
Xchar buffer[50];
Xchar *howdead;
X
Xfor(x=0;x<=ROWLEN;x++)
X    for(y=0;y<NOOFROWS;y++)
X	{
X        if(screen[y][x] == '@')
X	    {
X	    sx = x;
X	    sy = y;
X	    }
X        if(screen[y][x] == '-')
X        	screen[y][x] = ' ';
X        };
Xx=sx;
Xy=sy;
Xif(maxmoves != 0)
X(void) sprintf(buffer,"Moves remaining = %d   ",maxmoves);
Xelse
X(void) strcpy(buffer,"     Unlimited moves     ");
Xdebug_disp=1;
Xmap(frow);
Xmove(18,0);
Xaddstr(buffer);
X
X/* ACTUAL EDIT FUNCTION */
X
Xinstruct();
Xwhile(!quit)
X{
Xmove(y+1,x+1);
Xrefresh();
Xch = (char)getchar();
X
Xnx=x;
Xny=y;
X
Xif(ch == keys[3]||ch == keys[2]||ch == keys[1]||ch == keys[0])
X    {
X    if(ch == keys[3])
X	    nx++;
X    if(ch == keys[2])
X	    nx--;
X    if(ch == keys[1])
X	    ny++;
X    if(ch == keys[0])
X            ny--;
X    }
Xelse if(ch == 'q')
X    {
X    move(19,0);
X    addstr("                                                                          ");
X    break;
X    }
Xelse if(ch == 'm')              /* change to number of moves for the screen */
X    {
X    move(19,0);
X    addstr("How many moves for this screen? :");
X    refresh();echo();
X    scanf("%d",&maxmoves);noecho();
X    if(maxmoves < 0 ) maxmoves = 0;
X    move(19,0);
X    addstr("                                           ");
X    if(maxmoves != 0)
X        (void) sprintf(buffer,"Moves remaining = %d   ",maxmoves);
X    else
X        (void) strcpy(buffer,"     Unlimited moves     ");
X    move(18,0);
X    addstr(buffer);
X    refresh();            /* for some reason, this seems to add a '.' to */
X			  /* the map... Ive no idea why yet... */
X    }
Xelse if(ch == 'p' || ch == 'n')       /* play the game (test) */
X    {
X	noins();
X	wscreen(num,maxmoves);
X	if(ch == 'p')
X	    {
X	    debug_disp = 0;
X	    clear();
X	    }
X	*score = 0;
X	howdead = playscreen(&num,score,bell,maxmoves,keys);
X	move(20,0);
X	if(howdead!=0)
X	    addstr(howdead);
X	else
X	    addstr("DONE!");
X	printw("; hit any key to continue\n");
X	refresh();
X	ch = (char)getchar();
X	clear();
X	rscreen(num,&maxmoves);
X	debug_disp = 1;
X	map(frow);
X	instruct();
X    }
Xelse
X    {
X    if(ch >= 'a' && ch <= 'z') ch = ch - 'a' + 'A';
X    if(ch < ' ' || ch == (char)127) ch = '.';  /* no ctrl codes, thankyou */
X    if(ch == '"') ch = (char)getchar();
X    screen[y][x] = ch;
X    move(y+1,x+1);
X    addch(ch);
X    nx++;
X    }
Xif(nx < 0)
X    {
X    nx = ROWLEN-1;
X    ny--;
X    }
Xif(nx >= ROWLEN)
X    {
X    nx = 0;
X    ny++;
X    }
Xif(ny < 0) ny = NOOFROWS-1;
Xif(ny >= NOOFROWS) ny = 0;
Xmove(ny+1,nx+1);
Xx=nx;
Xy=ny;
X}
X
Xfor(y = 0; y<NOOFROWS;y++)       /* certain editors - eg ded - have a */
X			         /* habit of truncating trailing spaces*/
X		                 /* so this should stop them! */
X    if(screen[y][ROWLEN-1] == ' ')
X	screen[y][ROWLEN-1] = '-';
Xwscreen(num,maxmoves);
Xmove(20,0);
Xrefresh();
X}
END_OF_FILE
if test 3942 -ne `wc -c <'edit.c'`; then
    echo shar: \"'edit.c'\" unpacked with wrong size!
fi
# end of 'edit.c'
fi
if test -f 'fall.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fall.c'\"
else
echo shar: Extracting \"'fall.c'\" \(5261 characters\)
sed "s/^X//" >'fall.c' <<'END_OF_FILE'
X#include "wand_head.h"
X
Xextern void draw_symbol();
Xextern int debug_disp;
Xextern char screen[NOOFROWS][ROWLEN+1];
X
Xint check(mx,my,x,y,dx,dy,sx,sy,howdead)
X/* check for any falling caused by something moving out of x,y along
X   vector dx,dy. All the others are constant and should really have
X   been global... 						    */
Xint x,y,sx,sy,dx,dy, *mx, *my;
Xchar howdead[25];
X{
Xint ret=0;
Xret+=fall(mx,my,x,y,sx,sy,howdead);
Xret+=fall(mx,my,x-dx,y-dy,sx,sy,howdead);
Xret+=fall(mx,my,x-dy,y-dx,sx,sy,howdead);
Xret+=fall(mx,my,x+dy,y+dx,sx,sy,howdead);
Xret+=fall(mx,my,x-dx-dy,y-dy-dx,sx,sy,howdead);
Xret+=fall(mx,my,x-dx+dy,y-dy+dx,sx,sy,howdead);
Xreturn ret;
X}
X
Xint fall(mx,my,x,y,sx,sy,howdead)  /* recursive function for falling */
X				   /* boulders and arrows */
Xint  x,y,sx,sy, *mx, *my;
Xchar howdead[25];
X{
Xint nx = x,nyl = y,nyr = y,retval = 0;
Xif ((y>(NOOFROWS-1))||(y<0)||(x<0)||(x>(ROWLEN-1)))
X    return(0);
Xif((screen[y][x] != 'O') && (screen[y][x] != ' ') && (screen[y][x] != 'M') &&
X   (screen[y][x] !='\\') && (screen[y][x] != '/') && (screen[y][x] != '@'))
X    return(0);
Xif(screen[y][x] == 'O')
X    {
X    if((screen[y][x-1] == ' ') && (screen[y-1][x-1] == ' '))
X        nx--;
X    else
X	{
X        if((screen[y][x+1] == ' ') && (screen[y-1][x+1] == ' '))
X            nx++;
X	else
X	    nx = -1;
X	}
X    if((screen[y-1][x] == ' ') && (screen[y-1][x+1] == ' '))
X        nyr--;
X    else
X	{
X        if((screen[y+1][x] == ' ') && (screen[y+1][x+1] == ' '))
X            nyr++;
X	else
X	    nyr = -1;
X	}
X    if((screen[y-1][x] == ' ') && (screen[y-1][x-1] == ' '))
X        nyl--;
X    else
X	{
X        if((screen[y+1][x] == ' ') && (screen[y+1][x-1] == ' '))
X            nyl++;
X	else
X	    nyl = -1;
X	}
X    }
Xif(screen[y][x] == '\\')
X    {
X    if(screen[y-1][++nx] != ' ')
X	nx = -1;
X    if(screen[--nyr][x+1] != ' ')
X        nyr = -1;
X    if(screen[++nyl][x-1] != ' ')
X        nyl = -1;
X    }
Xif(screen[y][x] == '/')
X    {
X    if(screen[y-1][--nx] != ' ')
X	nx = -1;
X    if(screen[++nyr][x+1] != ' ')
X	nyr = -1;
X    if(screen[--nyl][x-1] != ' ')
X	nyl = -1;
X    }
Xif((screen[y][nx] != ' ') && (screen[y][nx] != 'M'))
X    nx = -1;
Xif((screen[y-1][x] == 'O') && (nx >= 0) && (y > 0)) /* boulder falls ? */
X    {
X    screen[y-1][x] = ' ';
X    if(screen[y][nx] == '@')
X        {
X    	strcpy(howdead,"a falling boulder");
X    	retval=1;
X    	}
X    if(screen[y][nx] == 'M')
X        {
X    	*mx = *my = -2;
X	screen[y][nx] = ' ';
X    	}
X    screen[y][nx] = 'O';
X    if(!debug_disp)
X	{
X        if((y<(sy+5)) && (y>(sy-3)) && (x>(sx-6)) && (x<(sx+6)))
X            draw_symbol((x-sx+5)*3,(y-sy+2)*2,' ');
X        if((y<(sy+4)) && (y>(sy-4)) && (nx>(sx-6)) && (nx<(sx+6)))
X            draw_symbol((nx-sx+5)*3,(y-sy+3)*2,'O');
X	}
X    else
X	{
X	move(y,x+1);
X	addch(' ');;
X	move(y+1,nx+1);
X	addch('O');
X    }
X    refresh();
X    retval+=fall(mx,my,nx ,y+1,sx,sy,howdead);
X    retval+=check(mx,my,x,y-1,0,1,sx,sy,howdead);
X    if(screen[y+1][nx] == '@')
X        {
X    	strcpy(howdead,"a falling boulder");
X    	return(1);
X    	}
X    if(screen[y+1][nx] == 'M')
X        {
X    	*mx = *my = -2;
X	screen[y+1][nx] = ' ';
X    	}
X    }
Xif((screen[nyr][x] != ' ')&&(screen[nyr][x] != 'M'))
X    nyr = -1;
Xif((screen[y][x+1] == '<')&&(nyr>=0)&&(x+1<ROWLEN)) /* arrow moves ( < ) ? */
X    {
X    screen[y][x+1] = ' ';
X    if(screen[nyr][x] == '@')
X        {
X    	strcpy(howdead,"a speeding arrow");
X    	retval = 1;
X    	}
X    if(screen[nyr][x] == 'M')
X        {
X    	*mx = *my = -2;
X	screen[nyr][x] = ' ';
X    	}
X    screen[nyr][x] = '<';
X    if(!debug_disp)
X	{
X        if((y<(sy+4)) && (y>(sy-4)) && (x<(sx+5)) && (x>(sx-7)))
X            draw_symbol((x-sx+6)*3,(y-sy+3)*2,' ');
X        if((nyr<(sy+4)) && (nyr>(sy-4)) && (x<(sx+6)) && (x>(sx-6)))
X            draw_symbol((x-sx+5)*3,(nyr-sy+3)*2,'<');
X	}
X    else
X	{
X	move(y+1,x+2);
X	addch(' ');
X	move(nyr+1,x+1);
X	addch('<');
X	}
X    refresh();
X    retval+=fall(mx,my,x-1,nyr,sx,sy,howdead);
X    retval+=check(mx,my,x+1,y,-1,0,sx,sy,howdead);
X    if(screen[nyr][x-1] == '@')
X        {
X    	strcpy(howdead,"a speeding arrow");
X    	return(1);
X    	}
X    if(screen[nyr][x-1] == 'M')
X        {
X    	*mx = *my = -2;
X	screen[nyr][x-1] = ' ';
X    	}
X    }
Xif((screen[nyl][x] != ' ')&&(screen[nyl][x] != 'M'))
X    nyl = -1;
Xif((screen[y][x-1] == '>')&&(nyl>=0)&&(x>0))       /* arrow moves ( > ) ? */
X    {
X    screen[y][x-1] = ' ';
X    if(screen[nyl][x] == '@')
X        {
X    	strcpy(howdead,"a speeding arrow");
X    	retval = 1;
X    	}
X    if(screen[nyl][x] == 'M')
X        {
X    	*mx = *my = -2;
X	screen[nyl][x] = ' ';
X    	}
X    screen[nyl][x] = '>';
X    if(!debug_disp)
X	{
X        if((y<(sy+4)) && (y>(sy-4)) && (x<(sx+7)) && (x>(sx-5)))
X            draw_symbol((x-sx+4)*3,(y-sy+3)*2,' ');
X        if((nyl<(sy+4)) && (nyl>(sy-4)) && (x<(sx+6)) && (x>(sx-6)))
X            draw_symbol((x-sx+5)*3,(nyl-sy+3)*2,'>');
X	}
X    else
X	{
X	move(y+1,x);
X	addch(' ');
X	move(nyl+1,x+1);
X	addch('>');
X	}
X    refresh();
X    retval+=fall(mx,my,x+1,nyl,sx,sy,howdead);
X    retval+=check(mx,my,x-1,y,1,0,sx,sy,howdead);
X    if(screen[nyl][x+1] == '@')
X        {
X    	strcpy(howdead,"a speeding arrow");
X    	return(1);
X    	}
X    if(screen[nyl][x+1] == 'M')
X        {
X    	*mx = *my = -2;
X	screen[nyl][x+1] = ' ';
X    	}
X    }
Xif(retval>0)
X    return(1);
Xreturn(0);
X}
END_OF_FILE
if test 5261 -ne `wc -c <'fall.c'`; then
    echo shar: \"'fall.c'\" unpacked with wrong size!
fi
# end of 'fall.c'
fi
if test -f 'game.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'game.c'\"
else
echo shar: Extracting \"'game.c'\" \(19193 characters\)
sed "s/^X//" >'game.c' <<'END_OF_FILE'
X#include "wand_head.h"
X
X#define viable(x,y) (((screen[y][x] == ' ') || (screen[y][x] == ':') ||\
X	(screen[y][x] == '@') || (screen[y][x] == '+')) && (y >= 0) &&\
X	(x >= 0) && (y < NOOFROWS) && (x < ROWLEN))
X
X/* typedef struct mon_rec		*//* M002 struct mon_rec moved	*/
X/*     {				*//* to header file because it 	*/
X/*     int x,y,mx,my;			*//* is needed by save.c	*/
X/*     char under;			*/
X/*     struct mon_rec *next,*prev;	*/
X/*     };				*/
X
Xtypedef struct { int d[2] } direction;
X
X#ifdef	LINT_ARGS	/* M001 */
Xdirection new_direction(int, int, int, int);
X#else
Xdirection new_direction();
X#endif
X
Xextern int jumpscreen();
X
Xextern int check();
X
Xextern void showpass();
X
Xextern void draw_symbol();
X
Xextern void display();
X
Xextern int fall();
X
Xextern void map();
X
Xextern int debug_disp;
Xextern int edit_mode;
Xextern int saved_game;
Xextern char screen[NOOFROWS][ROWLEN+1];
X
X/* Add a spirit to the chain */
X/* Maintain a doubly linked list to make reuse possible.
X   tail_of_list is *NOT* the last monster allocated, but
X   the last monster alloted to a screen.  start_of_list
X   is a dummy entry to ease processing. last_of_list
X   is the last entry allocated. */
Xstatic struct mon_rec start_of_list = {0,0,0,0,0,NULL,NULL};
X
Xstruct mon_rec *tail_of_list;
Xstruct mon_rec *last_of_list;
X
Xstruct mon_rec *make_monster(x,y)
Xint x,y;
X{
Xchar *malloc();
X#define MALLOC (struct mon_rec *)malloc(sizeof(struct mon_rec))
Xstruct mon_rec *monster;
Xif(tail_of_list->next == NULL)
X    {
X    if((last_of_list = MALLOC) == NULL)
X	return NULL;
X    tail_of_list->next = last_of_list;
X    last_of_list->prev = tail_of_list;
X    last_of_list->next = NULL;
X    }
Xmonster = tail_of_list = tail_of_list->next;
Xmonster->x = x;
Xmonster->y = y;
Xmonster->mx = 1;      /* always start moving RIGHT. (fix later)  */
Xmonster->my = 0;
Xmonster->under = ' ';
Xreturn monster;
X}
X
X/* 'follow lefthand wall' algorithm for baby monsters */
X
Xdirection new_direction(x,y,bx,by)
Xint x,y,bx,by;
X{
Xdirection out;
Xif(viable((x+by),(y-bx)))
X    {
X    out.d[0] = by;
X    out.d[1] = -bx;
X    return out;
X    }
Xif(viable((x+bx),(y+by)))
X    {
X    out.d[0] = bx;
X    out.d[1] = by;
X    return out;
X    }
Xif(viable((x-by),(y+bx)))
X    {
X    out.d[0] = -by;
X    out.d[1] = bx;
X    return out;
X    }
Xif(viable((x-bx),(y-by)))
X    {
X    out.d[0] = -bx;
X    out.d[1] = -by;
X    return out;
X    }
Xout.d[0] = -bx;
Xout.d[1] = -by;
Xreturn out;
X}
X
X/* Actual game function - Calls fall() to move
X       boulders and arrows recursively */
X/* Variable explaination :
X	All the var names make sense to ME, but some people think them a bit confusing... :-) So heres an explanation.
X   x,y : where you are
X   nx,ny : where you're trying to move to
X   sx,sy : where the screen window on the playing area is
X   mx,my : where the monster is
X   tx,ty : teleport arrival
X   bx,by : baby monster position
X   nbx,nby : where it wants to be
X   lx,ly : the place you left when teleporting
X   nf : how many diamonds youve got so far
X   new_disp : the vector the baby monster is trying
X*/
X
Xchar *playscreen(num,score,bell,maxmoves,keys)
Xint  *num, maxmoves,
X     *bell,
X     *score;
Xchar keys[10];
X{
Xint  x,y,nx,ny,deadyet =0,
X     sx = -1,sy = -1,tx = -1,ty = -1,lx = 0,ly = 0,mx = -1,my = -1,
X     bx, by, nbx, nby,
X     newnum,
X     max_score = 250,
X     diamonds = 0, nf = 0,hd ,vd ,xdirection,ydirection;
Xchar (*frow)[ROWLEN+1] = screen,
X     ch,
X     buffer[25];
Xstatic char     howdead[25];	/* M001 can't use auto var for return value */
Xdirection new_disp;
Xstruct mon_rec *monster,*current;
X
Xtail_of_list = &start_of_list;
X
Xfor(x=0;x<=ROWLEN;x++)
X    for(y=0;y<NOOFROWS;y++)
X	{
X	if((screen[y][x] == '*')||(screen[y][x] == '+'))
X	    {
X	    diamonds++;
X	    max_score += 10;
X	    if(screen[y][x] == '+')
X		max_score += 20;
X	    }
X        if(screen[y][x] == 'A')     /* note teleport arrival point &  */
X	    {                       /* replace with space */
X	    tx = x;
X	    ty = y;
X 	    screen[y][x] = ' ';
X	    }
X        if(screen[y][x] == '@')
X	    {
X	    sx = x;
X	    sy = y;
X	    }
X        if(screen[y][x] == 'M')     /* Put megamonster in */
X	    {
X	    mx = x;
X	    my = y;
X	    }
X	if(screen[y][x] == 'S')     /* link small monster to pointer chain */
X	    {
X	    if((monster = make_monster(x,y)) == NULL)
X		{
X		strcpy(howdead,"running out of memory");
X		return howdead;
X		}
X	    if(!viable(x,y-1))     /* make sure its running in the correct */
X		{                  /* direction..                          */
X		monster->mx = 1;
X		monster->my = 0;
X		}
X	    else if(!viable(x+1,y))
X		{
X		monster->mx = 0;
X		monster->my = 1;
X		}
X	    else if(!viable(x,y+1))
X		{
X		monster->mx = -1;
X		monster->my = 0;
X		}
X	    else if(!viable(x-1,y))
X		{
X		monster->mx = 0;
X		monster->my = -1;
X		}
X	    }
X        if(screen[y][x] == '-')
X        	screen[y][x] = ' ';
X        };
Xx=sx;
Xy=sy;
Xif((x == -1)&&(y == -1))              /* no start position in screen ? */
X    {
X    strcpy(howdead,"a screen design error");
X    return(howdead);
X    }
X
Xupdate_game:	/* M002  restored game restarts here	*/
X
Xmove(0,48);
X(void) addstr("Score\t   Diamonds");
Xmove(1,48);
X(void) addstr("\tFound\tTotal");
Xmove(3,48);
X(void) sprintf(buffer,"%d\t %d\t %d  ",*score,nf,diamonds);
X(void) addstr(buffer);
Xmove(6,48);
X(void) sprintf(buffer,"Current screen %d",*num);
X(void) addstr(buffer);
Xif(maxmoves != 0)
X(void) sprintf(buffer,"Moves remaining = %d   ",maxmoves);
Xelse
X{
X    (void) strcpy(buffer,"     Unlimited moves     ");
X    maxmoves = -1;
X};
Xmove(15,48);
X(void) addstr(buffer);
Xif(mx != -1)                            /* tell player if monster exists */
X    draw_symbol(48,10,'M');
Xelse
X    draw_symbol(48,10,' ');
X
Xif(!debug_disp)
X    display(sx,sy,frow,*score);
Xelse
X    map(frow);
X
X/* ACTUAL GAME FUNCTION - Returns method of death in string  */
X
Xwhile(deadyet == 0)
X{
Xch = getch();
X
Xnx=x;
Xny=y;
X
Xif(ch == keys[3])              /* move about - but thats obvious */
X	nx++;
Xif(ch == keys[2])
X	nx--;
Xif((ch == keys[1]) && (y<(NOOFROWS-1)))
X	ny++;
Xif(ch == keys[0])
X        ny--;
Xif(ch == '1')                  /* Add or get rid of that awful sound */
X	{
X        move(10,45);
X        *bell = 1;
X        (void) addstr("Bell ON ");
X	move(16,0);
X        refresh();
X	continue;
X	}
Xif(ch == '0')
X	{
X        *bell = 0;
X        move(10,45);
X        (void) addstr("Bell OFF");
X	move(16,0);
X        refresh();
X	continue;
X	}
Xif(ch == '~')                             /* level jump */
X	{
X	if((newnum = jumpscreen(*num)) == 0)
X	    {
X	    strcpy(howdead,"a jump error.");
X	    return howdead;
X	    }
X	if(newnum != *num)
X	    {                  /* Sorry Greg, no points for free */
X	    sprintf(howdead,"~%c",newnum);
X	    return howdead;
X	    }
X	continue;
X	}
Xif(ch == '!')                      /* look at the map */
X	{
X	if(debug_disp)
X	    continue;
X	map(frow);
X        display(sx,sy,frow,*score);
X	continue;
X	}
Xif(ch == 'q')
X        {
X        strcpy(howdead,"quitting the game");
X	return howdead;
X	}
Xif(ch == '?')
X	{
X	helpme();
X	display(sx,sy,frow,*score);
X	continue;
X	}
X
X/* M002  Added save/restore game feature.  Gregory H. Margo	*/
Xif(ch == 'S')           /* save game */
X	{
X	extern	struct	save_vars	zz;
X
X	/* stuff away important local variables to be saved */
X	/* so the game state may be acurately restored	*/
X	zz.z_x		= x;
X	zz.z_y		= y;
X	zz.z_nx		= nx;
X	zz.z_ny		= ny;
X	zz.z_sx		= sx;
X	zz.z_sy		= sy;
X	zz.z_tx		= tx;
X	zz.z_ty		= ty;
X	zz.z_lx		= lx;
X	zz.z_ly		= ly;
X	zz.z_mx		= mx;
X	zz.z_my		= my;
X	zz.z_bx		= bx;
X	zz.z_by		= by;
X	zz.z_nbx	= nbx;
X	zz.z_nby	= nby;
X	zz.z_max_score	= max_score;
X	zz.z_diamonds	= diamonds;
X	zz.z_nf		= nf;
X	zz.z_hd		= hd;
X	zz.z_vd		= vd;
X	zz.z_xdirection	= xdirection;
X	zz.z_ydirection	= ydirection;
X
X	save_game(*num, score, bell, maxmoves, &start_of_list, tail_of_list);
X	/* NOTREACHED */
X	}
Xif(ch == 'R')    	/* restore game */
X	{
X	extern	struct	save_vars	zz;
X
X	restore_game(num, score, bell, &maxmoves, &start_of_list, &tail_of_list);
X
X	/* recover important local variables */
X	x		= zz.z_x;
X	y		= zz.z_y;
X	nx		= zz.z_nx;
X	ny		= zz.z_ny;
X	sx		= zz.z_sx;
X	sy		= zz.z_sy;
X	tx		= zz.z_tx;
X	ty		= zz.z_ty;
X	lx		= zz.z_lx;
X	ly		= zz.z_ly;
X	mx		= zz.z_mx;
X	my		= zz.z_my;
X	bx		= zz.z_bx;
X	by		= zz.z_by;
X	nbx		= zz.z_nbx;
X	nby		= zz.z_nby;
X	max_score	= zz.z_max_score;
X	diamonds	= zz.z_diamonds;
X	nf		= zz.z_nf;
X	hd		= zz.z_hd;
X	vd		= zz.z_vd;
X	xdirection	= zz.z_xdirection;
X	ydirection	= zz.z_ydirection;
X
X	if (maxmoves == -1)
X		maxmoves = 0;	/* to get the "unlimited moves" message */
X
X	goto update_game;	/* the dreaded goto	*/
X	}
X
Xif(screen[ny][nx] == 'C')
X    {
X    screen[ny][nx] = ':';
X    *score+=4;
X    if(maxmoves != -1)
X        maxmoves+=250;
X    }
Xswitch(screen[ny][nx])
X    {
X    case '@': break;
X    case '*': *score+=9;
X	max_score -= 10;
X        nf++;
X    case ':': *score+=1;
X        move(3,48);
X        sprintf(buffer,"%d\t %d",*score,nf);
X        (void) addstr(buffer);
X    case ' ':
X	screen[y][x] = ' ';
X   	screen[ny][nx] = '@';
X	if(!debug_disp)
X	    {
X    	    draw_symbol((x-sx+5)*3,(y-sy+3)*2,' ');
X    	    draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@');
X	    }
X	else
X	    {
X	    move(y+1,x+1);
X	    addch(' ');
X	    move(ny+1,nx+1);
X	    addch('@');
X	    }
X	deadyet += check(&mx,&my,x,y,nx-x,ny-y,sx,sy,howdead);
X    	move(16,0);
X    	refresh();
X	y = ny;
X	x = nx;
X        break;
X    case 'O':
X	if(screen[y][nx*2-x] == 'M')
X	    {
X	    screen[y][nx*2-x] = ' ';
X	    mx = my = -1;
X	    *score+=100;
X            move(3,48);
X            sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds);
X            (void) addstr(buffer);
X	    draw_symbol(48,10,' ');
X	    move(16,0);
X            refresh();
X	    }
X	if(screen[y][nx*2-x] == ' ')
X	    {
X	    screen[y][nx*2-x] = 'O';
X	    screen[y][x] = ' ';
X            screen[ny][nx] = '@';
X	    if(!debug_disp)
X		{
X                draw_symbol((x-sx+5)*3,(y-sy+3)*2,' ');
X                draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@');
X		if(nx*2-x>sx-6&&nx*2-x<sx+6)
X                    draw_symbol((nx*2-x-sx+5)*3,(y-sy+3)*2,'O');
X		}
X	    else
X		{
X		move(y+1,x+1);
X		addch(' ');
X		move(ny+1,nx+1);
X		addch('@');
X		move(y+1,nx*2-x+1);
X		addch('O');
X		}
X            deadyet += fall(&mx,&my,nx*2-x,y+1,sx,sy,howdead);
X            deadyet += fall(&mx,&my,x*2-nx,y,sx,sy,howdead);
X            deadyet += fall(&mx,&my,x,y,sx,sy,howdead);
X            deadyet += fall(&mx,&my,x,y-1,sx,sy,howdead);
X            deadyet += fall(&mx,&my,x,y+1,sx,sy,howdead);
X            move(16,0);
X            refresh();
X	    y = ny;
X	    x = nx;
X	    }
X	break;
X    case '<':
X    case '>':
X	if(screen[ny*2-y][x] == 'M')
X	    {
X	    screen[ny*2-y][x] = ' ';
X	    mx = my = -1;
X	    *score+=100;
X            move(3,48);
X            sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds);
X            (void) addstr(buffer);
X	    draw_symbol(48,10,' ');
X	    move(16,0);
X            refresh();
X	    }
X	if(screen[ny*2-y][x] == ' ')
X	    {
X	    screen[ny*2-y][x] = screen[ny][nx];
X	    screen[y][x] = ' ';
X            screen[ny][nx] = '@';
X	    if(!debug_disp)
X		{
X                draw_symbol((x-sx+5)*3,(y-sy+3)*2,' ');
X                draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@');
X		if(ny*2-y>sy-4&&ny*2-y<sy+4)
X                    draw_symbol((x-sx+5)*3,(ny*2-y-sy+3)*2,screen[ny*2-y][x]);
X		}
X	    else
X		{
X		move(y+1,x+1);
X		addch(' ');
X		move(ny+1,nx+1);
X		addch('@');
X		move(ny*2-y+1,x+1);
X		addch(screen[ny*2-y][x]);
X		}
X	        deadyet += fall(&mx,&my,x,y,sx,sy,howdead);
X	        deadyet += fall(&mx,&my,x-1,(ny>y)?y:(y-1),sx,sy,howdead);
X	        deadyet += fall(&mx,&my,x+1,(ny>y)?y:(y-1),sx,sy,howdead);
X	        deadyet += fall(&mx,&my,x-1,ny*2-y,sx,sy,howdead);
X	        deadyet += fall(&mx,&my,x+1,ny*2-y,sx,sy,howdead);
X            move(16,0);
X            refresh();
X	    y = ny;
X	    x = nx;
X	    }
X	break;
X    case '!':
X        strcpy(howdead,"an exploding landmine");
X	deadyet = 1;
X	if(!debug_disp)
X	    {
X    	    draw_symbol((x-sx+5)*3,(y-sy+3)*2,' ');
X    	    draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@');
X	    }
X	else
X	    {
X	    move(y+1,x+1);
X	    addch(' ');
X	    move(ny+1,nx+1);
X	    addch('@');
X	    }
X        move(16,0);
X	refresh();
X        break;
X    case 'X':
X	if(nf == diamonds)
X	    {
X	    *score+=250;
X	    showpass(*num);
X	    return NULL;
X	    }
X	break;
X    case 'T':
X	if(tx > -1)
X	    {
X	    screen[ny][nx] = ' ';
X	    screen[y][x] = ' ';
X	    lx = x;
X	    ly = y;
X	    y = ty;
X	    x = tx;
X	    screen[y][x] = '@';
X	    sx = x;
X	    sy = y;
X	    *score += 20;
X            move(3,48);
X            sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds);
X            (void) addstr(buffer);
X	    if(!debug_disp)
X	        display(sx,sy,frow,*score);
X	    else
X		map(frow);
X	    deadyet = fall(&mx,&my,nx,ny,sx,sy,howdead);
X	    if(deadyet == 0)
X		deadyet = fall(&mx,&my,lx,ly,sx,sy,howdead);
X	    if(deadyet == 0)
X		deadyet = fall(&mx,&my,lx+1,ly-1,sx,sy,howdead);
X	    if(deadyet == 0)
X		deadyet = fall(&mx,&my,lx+1,ly+1,sx,sy,howdead);
X	    if(deadyet == 0)
X		deadyet = fall(&mx,&my,lx-1,ly+1,sx,sy,howdead);
X	    if(deadyet == 0)
X		deadyet = fall(&mx,&my,lx-1,ly-1,sx,sy,howdead);
X	    move(16,0);
X	    refresh();
X	    }
X	else
X	    {
X	    screen[ny][nx] = ' ';
X	    printf("Teleport out of order");
X	    }
X	break;
X    case 'M':
X	strcpy(howdead,"a hungry monster");
X	deadyet = 1;
X	if(!debug_disp)
X    	    draw_symbol((x-sx+5)*3,(y-sy+3)*2,' ');
X	else
X	    {
X	    move(y+1,x+1);
X	    addch(' ');
X	    }
X        move(16,0);
X	refresh();
X        break;
X    case 'S':
X	strcpy(howdead,"walking into a monster");
X	deadyet = 1;
X	if(!debug_disp)
X    	    draw_symbol((x-sx+5)*3,(y-sy+3)*2,' ');
X	else
X	    {
X	    move(y+1,x+1);
X	    addch(' ');
X	    }
X        move(16,0);
X	refresh();
X        break;
X    default:
X        break;
X    }
Xif((y == ny) && (x == nx) && (maxmoves>0))
X    {
X    (void) sprintf(buffer,"Moves remaining = %d ",--maxmoves);
X    move(15,48);
X    (void) addstr(buffer);
X    }
Xif(maxmoves == 0)
X    {
X    strcpy(howdead,"running out of time");
X    return(howdead);
X    }
Xif(!debug_disp)
X    {
X    if ((x<(sx-3))&& (deadyet ==0))         /* screen scrolling if necessary */
X        {
X        sx-=6;
X        if(sx < 4)
X	    sx = 4;
X        display(sx,sy,frow,*score);
X        }
X    if ((y<(sy-2))&& (deadyet == 0))
X        {
X        sy-=5;
X        if(sy < 2)
X	    sy = 2;
X        display(sx,sy,frow,*score);
X        }
X    if ((x>(sx+3)) && (deadyet == 0))
X        {
X        sx+=6;
X        if(sx>(ROWLEN -5))
X	    sx = ROWLEN -5;
X        display(sx,sy,frow,*score);
X        }
X    if ((y>(sy+2))&& (deadyet ==0))
X        {
X        sy+=5;
X        if(sy > (NOOFROWS-3))
X	    sy = NOOFROWS -3;
X        display(sx,sy,frow,*score);
X        }
X    }
X
X	/* MONSTER SECTION  */
X
X/* big monster first */
Xif(mx == -2)                              /* has the monster been killed ? */
X    {
X    *score+=100;
X    mx = my = -1;
X    move(3,48);
X    sprintf(buffer,"%d\t %d\t",*score,nf);
X    (void) addstr(buffer);
X    draw_symbol(48,10,' ');
X    move(16,0);
X    refresh();
X    }                                     /* if monster still alive */
Xif(mx != -1)                              /* then move that monster ! */
X    {
X    screen[my][mx] = ' ';
X    if(mx>x)
X        xdirection = -1;
X    else
X        xdirection = 1;
X    if(!debug_disp)
X	{
X        if((my<(sy+4))&&(my>(sy-4))&&(mx<(sx+6))&&(mx>(sx-6)))
X            draw_symbol((mx-sx+5)*3,(my-sy+3)*2,' ');
X	}
X    else
X	{
X	move(my+1,mx+1);
X	addch(' ');
X	}
X    if((hd = (mx-x))<0)
X	hd = -hd;
X    if((vd = (my-y))<0)
X	vd = -vd;
X    if((hd>vd)&&((screen[my][mx+xdirection] == ' ')||(screen[my][mx+xdirection] == '@')))
X	mx+=xdirection;
X    else
X        {
X        if(my>y)
X            ydirection = -1;
X	else
X    	    ydirection = 1;
X        if((screen[my+ydirection][mx] == ' ')||(screen[my+ydirection][mx] == '@'))
X	    my+=ydirection;
X	else
X            if((screen[my][mx+xdirection] == ' ')||(screen[my][mx+xdirection] == '@'))
X	mx+=xdirection;
X	}
X    if(!debug_disp)
X	{
X        if((my<(sy+4))&&(my>(sy-4))&&(mx<(sx+6))&&(mx>(sx-6)))
X            draw_symbol((mx-sx+5)*3,(my-sy+3)*2,'M');
X	}
X    else
X	{
X	move(my+1,mx+1);
X	addch('M');
X	}
X    if(screen[my][mx] == '@')                     /* ha! gottim! */
X	{
X	strcpy(howdead,"a hungry monster");
X        move(16,0);
X	refresh();
X        return(howdead);
X	}
X    screen[my][mx] = 'M';
X    move(16,0);
X    refresh();
X    }
X
Xcurrent = &start_of_list;
Xwhile((current != tail_of_list)&&(!deadyet))
X    /* deal with those little monsters */
X    {
X    monster = current->next;
X    new_disp = new_direction( monster->x, monster->y, monster->mx, monster->my );
X    if(monster->under!='S')
X	{
X        screen[monster->y][monster->x] = monster->under;
X        if(!debug_disp)
X	    {
X            if((monster->y < (sy+4)) && (monster->y > (sy-4)) && (monster->x < (sx+6)) && (monster->x > (sx-6)))
X                draw_symbol((monster->x-sx+5)*3,(monster->y-sy+3)*2,monster->under);
X	    }
X        else
X	    {
X	        move(monster->y+1,monster->x+1);
X	        addch(monster->under);
X	    }
X        if(monster->under == ' ')
X	     deadyet+=check(&mx,&my,monster->x,monster->y,new_disp.d[0],new_disp.d[1],sx,sy,howdead);
X	}
X    else
X	monster->under=' ';
X    monster->mx = new_disp.d[0];
X    monster->my = new_disp.d[1];
X    monster->x += monster->mx;
X    monster->y += monster->my;
X    monster->under = screen[monster->y][monster->x];
X    screen[monster->y][monster->x] = 'S';        /* move into new space */
X    if(!debug_disp)
X	{
X        if((monster->y < (sy+4)) && (monster->y > (sy-4)) && (monster->x < (sx+6)) && (monster->x > (sx-6)))
X            draw_symbol((monster->x-sx+5)*3,(monster->y-sy+3)*2,'S');
X	}
X    else
X	{
X	move(monster->y+1,monster->x+1);
X	addch('S');
X	}
X    if(monster->under == '@')                     /* monster hit you? */
X        {
X	strcpy(howdead,"the little monsters");
X	move(16,0);
X	refresh();
X        return(howdead);
X        }
X    if(monster->under == '+')                    /* monster hit cage? */
X        {
X	*score +=20;
X	max_score -= 20;
X        move(3,48);
X        sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds);
X        (void) addstr(buffer);
X        /* remove from chain, and insert at the end (at last_of_list) */
X	if(monster == tail_of_list)
X	    tail_of_list = tail_of_list->prev;
X	else
X	    {
X  	    current->next = monster-> next;
X	    current->next->prev = current;
X	    monster->next = NULL;
X	    monster->prev = last_of_list;
X	    last_of_list->next = monster;
X	    last_of_list = monster;
X	    }
X	screen[monster->y][monster->x] = '*';
X	if(!debug_disp)
X	    {
X            if((monster->y < (sy+4)) && (monster->y > (sy-4)) && (monster->x < (sx+6)) && (monster->x > (sx-6)))
X                    draw_symbol((monster->x-sx+5)*3,(monster->y-sy+3)*2,'*');
X	    }
X	else
X	    {
X	    move(monster->y+1,monster->x+1);
X	    addch('*');
X	    }
X        }
X    else
X	current = monster;
X    move(16,0);
X    refresh();
X    }
X
Xif((edit_mode)&&(deadyet)) {         /* stop death if testing */
X    if(!debug_disp)
X	move(18,0);
X    else
X	move(20,0);
X    addstr("You were killed by ");
X    addstr(howdead);
X    addstr("\nPress 'c' to continue.");
X    refresh();
X    ch=getch();
X    if(ch == 'c')
X	deadyet = 0;
X    if(!debug_disp)
X	move(18,0);
X     else
X	move(20,0);
X    addstr("                                                              ");
X    addstr("\n                      ");
X    refresh();
X    }
X
X}
Xreturn(howdead);
X}
END_OF_FILE
if test 19193 -ne `wc -c <'game.c'`; then
    echo shar: \"'game.c'\" unpacked with wrong size!
fi
# end of 'game.c'
fi
if test -f 'jump.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'jump.c'\"
else
echo shar: Extracting \"'jump.c'\" \(3969 characters\)
sed "s/^X//" >'jump.c' <<'END_OF_FILE'
X#include "wand_head.h"
X
Xextern int debug_disp;
Xextern int no_passwords;
Xextern int maxscreens;
X
Xint scrn_passwd(num, passwd)    /* reads password num into passwd */
Xint num;
Xchar *passwd;
X{
X	long position;
X	FILE *fp;
X
X	position = PASSWD;
X	while(position > 200000)
X		position -= 200000;
X	if((fp = fopen(DICTIONARY,"r")) == NULL)
X		return 0;
X	fseek(fp,position,ftell(fp));
X	while(fgetc(fp) != '\n');
X	fscanf(fp,"%s\n",passwd);
X	/* read a word into passwd */
X	fclose(fp);
X	return (1);
X}
X
Xvoid showpass(num)
Xint num;
X{
Xlong position;
Xchar correct[20];
Xchar buffer[100];
XFILE *fp;
Xchar ch;
Xif(no_passwords)
X    return;
Xif(!debug_disp)
X    move(18,0);
Xelse
X    move(20,0);
Xif(!scrn_passwd(num,correct))
X    return;
X(void) sprintf(buffer,"The password to jump to level %d ( using ~ ) is : %s        \n",(num+1),correct);
Xaddstr(buffer);
Xaddstr("PRESS ANY KEY TO REMOVE IT AND CONTINUE                          \n");
Xrefresh();
Xch = getch();
Xif(!debug_disp)
X    move(18,0);
Xelse
X    move(20,0);
Xaddstr("                                                                        \n");
Xaddstr("                                              ");
Xif(!debug_disp)
X    move(18,0);
Xelse
X    move(20,0);
Xrefresh();
X}
X
Xint jumpscreen(num)
Xint num;
X{
Xchar word[20],
X     buffer[100],
X     correct[20];
Xint index=0, input;
Xchar ch;
Xlong position;
Xint  fp, scrn;
X
Xif(no_passwords == 1) {
X    if(!debug_disp)
X        move(16,0);
X    else
X        move(18,0);
X    addstr("Enter number of desired level.\n");
X    refresh();
X    scrn = getnum();
X    if(scrn > num) {
X        if(!debug_disp)
X            move(16,0);
X        else
X            move(18,0);
X        addstr("                                                ");
X	return scrn;
X	}
X    if(!debug_disp)
X        move(16,0);
X    else
X        move(18,0);
X    addstr("No way, Jose! Back-jumping is prohibited!");
X    refresh();
X    return num;
X    }
X
Xif(!debug_disp)
X    move(16,0);
Xelse
X    move(18,0);
Xaddstr("Please enter password of screen to jump to:");
Xrefresh();
Xwhile(((word[index++] = getch()) != '\n')&&(index < 19))
X    {
X    addch('*');
X    refresh();
X    }
Xword[--index]='\0';
Xif(!debug_disp)
X    move(16,0);
Xelse
X    move(18,0);
Xaddstr("Validating...                                             \n");
Xrefresh();
X
Xif(strcmp(word,MASTERPASSWORD) == 0)
X    {
X    if(!debug_disp)
X        move(16,0);
X    else
X        move(18,0);
X    addstr("Enter number of desired level.");
X    refresh();
X    num = getnum();
X    (void) scrn_passwd(num-1,correct);
X    sprintf(buffer,"Certainly master, but the correct word is %s.       \n",correct);
X    if(!debug_disp)
X        move(16,0);
X    else
X        move(18,0);
X    addstr(buffer);
X    addstr("PRESS ANY KEY TO REMOVE IT AND CONTINUE                          \n");
X    refresh();
X    getchar();
X    if(!debug_disp)
X        move(16,0);
X    else
X        move(18,0);
X    addstr("                                                             ");
X    if(!debug_disp)
X        move(17,0);
X    else
X        move(19,0);
X    addstr("                                                             ");
X    if(!debug_disp)
X        move(16,0);
X    else
X 	move(18,0);
X    refresh();
X    return num;
X    }
X
Xfor(scrn = num;scrn < maxscreens;scrn++) {
X    if(!scrn_passwd(scrn,correct))
X	break;
X    if(strcmp(correct,word) == 0)
X        {
X        if(!debug_disp)
X            move(16,0);
X        else
X            move(18,0);
X        addstr("Password Validated..... Jumping to desired screen.        ");
X        refresh();
X        return ++scrn;
X        }
X    }
X
Xif(!debug_disp)
X    move(16,0);
Xelse
X    move(18,0);
X        addstr("PASSWORD NOT RECOGNISED!                    ");
Xrefresh();
Xif(!debug_disp)
X    move(16,0);
Xelse
X    move(18,0);
Xaddstr("                                                          ");
X
Xreturn num;
X}
X
Xint getnum()
X{
Xchar ch;
Xint num = 0;
X    for(ch = getch(),addch(ch),refresh(); ch >= '0' && ch <= '9'; ch = getch(),addch(ch),refresh())
X	{
X	num = num * 10 + ch - '0';
X	}
X    return num;
X}
END_OF_FILE
if test 3969 -ne `wc -c <'jump.c'`; then
    echo shar: \"'jump.c'\" unpacked with wrong size!
fi
# end of 'jump.c'
fi
if test -f 'read.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'read.c'\"
else
echo shar: Extracting \"'read.c'\" \(1154 characters\)
sed "s/^X//" >'read.c' <<'END_OF_FILE'
X#include "wand_head.h"
X
Xextern int edit_mode;
Xextern char screen[NOOFROWS][ROWLEN+1];
X
Xint rscreen(num,maxmoves)
Xint *maxmoves, num;
X{
Xint  y;
XFILE *fp;
Xchar name[50];
Xchar (*row_ptr)[ROWLEN+1] = screen;
Xif(!edit_mode)
X    sprintf(name,"%s/screen.%d",SCREENPATH,num);
Xelse
X    sprintf(name,"./screen");
Xfp = fopen(name,"r");
Xif(fp == NULL)
X    printf("\nFile for screen %d unavailable.\n\n",num) ;
Xelse
X    {
X    for(y = 0;y<NOOFROWS;y++)
X        {
X        fgets((*row_ptr++),ROWLEN + 1,fp);
X	fgetc(fp);                         /* remove newline char*/
X	};
X    if(fscanf(fp,"%*s\n%d",maxmoves) != 1)
X	*maxmoves=0;
X    fclose(fp);
X    };
Xreturn (fp == NULL);
X}
X
Xint wscreen(num,maxmoves)
Xint maxmoves, num;
X{
Xint  y,x;
XFILE *fp;
Xchar (*row_ptr)[ROWLEN+1] = screen;
Xfp = fopen("./screen","w");
Xif(fp == NULL)
X    printf("\nFile for screen cannot be written.\n\n") ;
Xelse
X    {
X    for(y = 0;y<NOOFROWS;y++)
X        {
X	for(x = 0;x<ROWLEN;x++)
X	    fputc(row_ptr[y][x],fp);
X	fputc('\n',fp);
X	};
X    for(x = 0; x<ROWLEN;x++)
X	fputc('#',fp);
X    fputc('\n',fp);
X    if(maxmoves != 0)
X	fprintf(fp,"%d\n",maxmoves);
X    fclose(fp);
X    };
Xreturn (fp == NULL);
X}
END_OF_FILE
if test 1154 -ne `wc -c <'read.c'`; then
    echo shar: \"'read.c'\" unpacked with wrong size!
fi
# end of 'read.c'
fi
if test -f 'scores.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'scores.c'\"
else
echo shar: Extracting \"'scores.c'\" \(5703 characters\)
sed "s/^X//" >'scores.c' <<'END_OF_FILE'
X#include "wand_head.h"
X
X#ifdef	MSDOS	/* M001	*/
X#define	LOCK
X#define	UNLOCK
X#else
X#define LOCK while((lock = creat(LOCKPATH,0)) < 0)
X#define UNLOCK (void) unlink(LOCKPATH)
X#endif
X
X#define ENTRIES 15
X
X#ifndef	MSDOS	/* M001 */
Xextern int getuid();
X#else
X#define	 getuid()	0
X#endif
X
Xextern int saved_game;  /* prevent recording of hiscore if  */
X			/* NO_RESTORED_GAME_HISCORES is #def'd */
X
Xtypedef struct
X    {
X    char howdead[25];
X    char name[20];
X    int  score;
X    int  level;
X    int  uid;
X    } score_entry;
X
X#ifdef	LINT_ARGS	/* M001	*/
Xvoid show_scores(score_entry *,int );
Xint readtable(score_entry *);
X#else
Xvoid show_scores();
Xint readtable();
X#endif
X
Xvoid show_scores(table,num)
Xscore_entry *table;
Xint         num;
X{
Xint tot = num;
Xprintf("\nNo. Score Level           Names                 How they died\n");
Xprintf("=============================================================================\n");
Xwhile(num > 0)
X    {
X    num--;
X    printf("%2d %5d %3d      %-20s     killed by %-s\n",(tot - num),table->score,table->level,table->name,table->howdead);
X    table++;
X    }
Xprintf("\n\n");
X}
X
Xint readtable(table_ptr)
Xscore_entry *table_ptr;
X{
XFILE *fp;
Xint  numread;
Xif((fp = fopen(HISCOREPATH,R_BIN)) == NULL)
X    {
X    numread = 0;
X    }
Xelse
X    {
X    numread = fread( VOIDSTAR table_ptr, sizeof(score_entry), ENTRIES, fp);
X    fclose(fp);
X    }
Xreturn numread;
X}
X
Xint  savescore(howdead,score,level,name)
Xchar *howdead, *name;
Xint  score,level;
X{
Xscore_entry table[ENTRIES + 2],
X	    *table_ptr = table,new_entry,temp_entry;
Xint  numread,index = 1, numsaved, lock, already = 0, output_value = 1,
X     user_id;
XFILE *fp;
X#ifdef NO_RESTORED_GAME_HISCORES
Xif(saved_game) {
X	printf("No hiscores recorded from restored games.\n");
X        printf("\nWanderer (C) 1988  S.Shipway.\n\n");
X	return 1;
X}
X#endif
Xuser_id = getuid();
Xstrncpy(new_entry.howdead,howdead,25);
Xnew_entry.howdead[24] = '\0';	/* M002 strncpy does not null terminate */
Xstrncpy(new_entry.name,name,20);
Xnew_entry.name[19] = '\0';	/* M002 strncpy does not null terminate */
Xnew_entry.score = score;
Xnew_entry.level = level;
Xnew_entry.uid = user_id;
XLOCK;
Xnumread = readtable(table_ptr);
Xif (numread > 0)
X    if(table[numread-1].score > 99999)     /* stop system errors messing it up*/
X        {
X        numread--;
X        printf("Erasing spurious entry in table.\n");
X        }
Xif(score == 0)
X    {
X    show_scores(table,numread);
X    UNLOCK;
X    return 0;
X    }
Xif (numread > 0)
X    {
X    numread++; /* scan through until correct insertion point */
X    /* pass table entries with higher scores */
X    while((table_ptr->score > score)&&(index < numread))
X	{
X#ifdef	COMPARE_BY_NAME
X#define	SAMEUSER(p)	(strcmp((p)->name, name) == 0)
X#else
X#define	SAMEUSER(p)	((p)->uid == user_id)
X#endif
X	if(SAMEUSER(table_ptr))
X	    {
X	    already = 1;
X	    break;
X	    }
X	table_ptr++;
X	index++;
X	}
X    /* pass table entries with equal score but higher or equal level */
X    while((table_ptr->level>=level)&&(index<numread)&&(table_ptr->score==score))
X	{
X	if(SAMEUSER(table_ptr))
X	    {
X	    already = 1;
X	    break;
X	    }
X	table_ptr++;
X	index++;
X	}
X    /* if already found: done */
X    if(already == 1)
X	{
X	numread--;
X	show_scores(table,numread);
X	UNLOCK;
X	return numread;
X	}
X    /* shift down score list */
X    while(index < numread)
X	{
X	/* swap *table_ptr and new_entry */
X	temp_entry = *table_ptr;
X	*table_ptr = new_entry;
X	new_entry = temp_entry;
X	if(SAMEUSER(&new_entry))
X	    {
X	    already = 1;
X	    numread--; /* an older entry found */
X	    break;
X	    }
X	table_ptr++;
X	index++;
X	}
X    /* if all shifted without finding an older entry */
X    if(already==0)
X	*table_ptr = new_entry;
X    }
Xelse
X    {
X    printf("\nCreating new hiscore table.\n\n");
X    *table_ptr = new_entry;
X    numread++;
X    }
Xnumread = ( (numread > ENTRIES) ? ENTRIES : numread );
Xfp = fopen(HISCOREPATH,W_BIN);
Xtable_ptr = table;
Xnumsaved = fwrite( VOIDSTAR table_ptr, sizeof(score_entry), numread, fp);
Xchmod(HISCOREPATH,0666);
Xif(numsaved < numread)
X    {
X    printf("ERROR! Only %d items saved from %d !\n",numsaved,numread);
X    output_value = 0;
X    }
Xfclose(fp);
XUNLOCK;
Xshow_scores(table,numsaved);
Xreturn output_value;
X}
X
Xvoid delete_entry(num)
Xint num;
X{
Xscore_entry table[ENTRIES + 22],
X	    *table_ptr = table,
X	    new_entry,temp_entry;
Xint  numread,index = 1, numsaved, lock, output_value = 1;
XFILE *fp;
XLOCK;
Xnumread = readtable(table_ptr);
Xif (numread == 0) {
X    printf("Missing or unreadable hiscore table.\n\n");
X    UNLOCK;
X    exit(1);
X}
Xif (num > numread) {
X    printf("Invalid entry, choose again\n");
X    UNLOCK;
X    return;
X}
Xwhile(index < num)
X    {
X    index++;
X    table_ptr++;
X    }
Xwhile(index < numread)
X    {
X    index++;
X    *table_ptr = *(table_ptr+1);
X    table_ptr++;
X    }
Xnumread--;
Xfp = fopen(HISCOREPATH,W_BIN);
Xtable_ptr = table;
Xnumsaved = fwrite( VOIDSTAR table_ptr, sizeof(score_entry), numread, fp);
Xchmod(HISCOREPATH,0666);
Xif(numsaved < numread)
X    {
X    printf("ERROR! Only %d items saved from %d !\n",numsaved,numread);
X    output_value = 0;
X    }
Xfclose(fp);
XUNLOCK;
Xshow_scores(table,numsaved);
X}
X
Xerase_scores()
X{
Xint erasenum,numread,index = 0;
Xchar correct[20],c;
Xscore_entry table[ENTRIES + 2],
X	    *table_ptr = table;
Xprintf("Please enter password:");
Xwhile((c = getchar()) != '\n' && index <19) {
X    correct[index++] = c;
X    }
Xcorrect[index] = 0;
Xif(strcmp(correct,MASTERPASSWORD))
X    {
X    printf("\nFoo, charlatan!\n");
X    return 0;
X    }
Xnumread = readtable(table_ptr);
Xshow_scores(table,numread);
Xprintf("\n");
Xfor(;;)
X{
Xprintf("Number to erase (0 to exit): ");
Xscanf("%d",&erasenum);
Xprintf("\n");
Xif(erasenum == 0)
X    break;
Xdelete_entry(erasenum);
Xprintf("\n");
X}
Xprintf("Byee!\n");
X}
END_OF_FILE
if test 5703 -ne `wc -c <'scores.c'`; then
    echo shar: \"'scores.c'\" unpacked with wrong size!
fi
# end of 'scores.c'
fi
if test ! -d 'screens' ; then
    echo shar: Creating directory \"'screens'\"
    mkdir 'screens'
fi
if test -f 'screens/no_pws' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'screens/no_pws'\"
else
echo shar: Extracting \"'screens/no_pws'\" \(0 characters\)
sed "s/^X//" >'screens/no_pws' <<'END_OF_FILE'
END_OF_FILE
if test 0 -ne `wc -c <'screens/no_pws'`; then
    echo shar: \"'screens/no_pws'\" unpacked with wrong size!
fi
# end of 'screens/no_pws'
fi
if test -f 'wand_head.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'wand_head.h'\"
else
echo shar: Extracting \"'wand_head.h'\" \(3966 characters\)
sed "s/^X//" >'wand_head.h' <<'END_OF_FILE'
X#include <stdio.h>
X#include <curses.h>
X#include <string.h>
X#include <fcntl.h>
X
X/* I wouldnt change these if I were you - it wont give you a bigger screen */
X#define ROWLEN 40
X#define NOOFROWS 16
X
X/* Change these to the necessary directories or files */
X#define SCREENPATH "/usr/games/lib/wand/screens"
X#define HISCOREPATH "/usr/games/lib/wand/hiscore"
X#define LOCKPATH "/tmp/wanderer.lock"      /* hiscore lock file */
X#define DICTIONARY "/usr/dict/words"
X
X/* change this to anything, but dont forget what */
X#define MASTERPASSWORD "something else"
X
X/* change the numbers in this as well, but keep it in the same form */
X#define PASSWD (num * num * 4373 + num * 16927 + 39)
X
X/* cbreak switching via curses package. */
X/* on some Ultrix systems you may need to use crmode() and nocrmode() */
X/* if so, just change the #defs to the necessary. I also know that Xenix */
X/* systems have to use crmode, so.. */
X#ifdef XENIX
X#define CBON crmode()
X#define CBOFF nocrmode()
X#else
X#define CBON cbreak()
X#define CBOFF nocbreak()
X#endif
X
X/* To disable the recording of hiscores from games restored from saves */
X/* #define NO_RESTORED_GAME_HISCORES  */
X
X/* MSDOS modifications (M001) by Gregory H. Margo	*/
X#ifdef	MSDOS
X#define	R_BIN	"rb"	/* binary mode for non-text files */
X#define	W_BIN	"wb"
X# ifdef	VOIDPTR
X#  define VOIDSTAR	(void *)
X# else
X#  define VOIDSTAR	(char *)
X# endif
X#define	ASKNAME		/* ask user's name if not in environment */
X#define	COMPARE_BY_NAME	/* compare users with name, not uid	*/
X#undef	getchar		/* remove stdio's definition to use curses' 	*/
X#define	getchar()	getch()	/* use curse's definition instead */
X
X#else /* not MSDOS */
X#define	R_BIN	"r"
X#define	W_BIN	"w"
X#define	VOIDSTAR
X#endif
X
X/* Save and Restore game additions (M002) by Gregory H. Margo	*/
X/* mon_rec structure needed by save.c */
Xstruct mon_rec
X    {
X    int x,y,mx,my;
X    char under;
X    struct mon_rec *next,*prev;
X    };
X
X
Xstruct	save_vars	{
X	int	z_x, z_y,
X		z_nx, z_ny,
X		z_sx, z_sy,
X		z_tx, z_ty,
X		z_lx, z_ly,
X		z_mx, z_my,
X		z_bx, z_by,
X		z_nbx, z_nby,
X		z_max_score,
X		z_diamonds,
X		z_nf,
X		z_hd,
X		z_vd,
X		z_xdirection,
X		z_ydirection
X};
X
X/* prototypes added by Gregory H. Margo */
X#ifdef	LINT_ARGS	/* M001 */
X/* DISPLAY.c */
Xextern  void map(char (*)[ROWLEN+1]);
Xextern  void display(int ,int ,char (*)[ROWLEN+1],int );
X
X/* EDIT.C */
Xextern  void instruct(void);
Xextern  void noins(void);
Xextern  void editscreen(int ,int *,int *,int ,char *);
X
X/* FALL.C */
Xextern  int check(int *,int *,int ,int ,int ,int ,int ,int ,char *);
Xextern  int fall(int *,int *,int ,int ,int ,int ,char *);
X
X/* GAME.C */
Xextern  struct mon_rec *make_monster(int ,int );
Xextern  char *playscreen(int *,int *,int *,int ,char *);
X
X/* ICON.C */
Xextern  void draw_symbol(int ,int ,char );
X
X/* JUMP.C */
Xextern  int scrn_passwd(int ,char *);
Xextern  void showpass(int );
Xextern  int jumpscreen(int );
Xextern  int getnum(void);
X
X/* READ.C */
Xextern  int rscreen(int ,int *);
Xextern  int wscreen(int ,int );
X
X/* SAVE.C */
Xextern  void save_game(int ,int *,int *,int ,struct mon_rec *,struct mon_rec *);
Xextern  void restore_game(int *,int *,int *,int *,struct mon_rec *,struct mon_rec **);
X
X/* SCORES.C */
Xextern  int savescore(char *,int ,int ,char *);
Xextern  void delete_entry(int );
Xextern  int erase_scores(void);
X
X#else
X
X/* DISPLAY.c */
Xextern  void map();
Xextern  void display();
X
X/* EDIT.C */
Xextern  void instruct();
Xextern  void noins();
Xextern  void editscreen();
X
X/* FALL.C */
Xextern  int check();
Xextern  int fall();
X
X/* GAME.C */
Xextern  struct mon_rec *make_monster();
Xextern  char *playscreen();
X
X/* ICON.C */
Xextern  void draw_symbol();
X
X/* JUMP.C */
Xextern  int scrn_passwd();
Xextern  void showpass();
Xextern  int jumpscreen();
Xextern  int getnum();
X
X/* READ.C */
Xextern  int rscreen();
Xextern  int wscreen();
X
X/* SAVE.C */
Xextern  void save_game();
Xextern  void restore_game();
X
X/* SCORES.C */
Xextern  int savescore();
Xextern  void delete_entry();
Xextern  int erase_scores();
X
X#endif
END_OF_FILE
if test 3966 -ne `wc -c <'wand_head.h'`; then
    echo shar: \"'wand_head.h'\" unpacked with wrong size!
fi
# end of 'wand_head.h'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0