[comp.sources.games] v06i027: sokoban2 - curses based, get the money game

games@tekred.CNA.TEK.COM (03/16/89)

Submitted-by: "H.Bernau" <uunet.uu.net!unido!tub!astbe!ber>
Posting-number: Volume 6, Issue 27
Archive-name: sokoban2/Part01

	[This is version 2 of sokoban.  In addition to some fixes and
	 enhancements, it contains some more screens.  The author says
	 he has played and solved all of the screens.   -br]

#! /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 Makefile README.v2 play.c save.c score.c
#   screen.29 showscreen.c sok.c sokoban.h
# Wrapped by billr@saab on Wed Mar 15 15:48:43 1989
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'\" \(1552 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is SOKOBAN.
X
XI saw this game first on a PC running MSDOS. I found the idea of the game so
Xclever, that I made up my mind to make it run with an ascii terminal using
Xcurses so that we can play it on our MicroVAX/ULTRIX. 
X
XAlong with this package there are alot of screen files describing the various
Xplay levels. So what you need to do to install it on your own machine is:
X
X-   Edit the header file sokoban.h to alter the given defines
X
XYou have to note the following restrictions
X
X-   The screen files must be readable for everyone who should be able to play
X    his game
X-   The score file should have read/write permission only for the owner
X    of the executable program. Because of that sokoban must run with setuid.
X
XYou can now compile it (just type 'make').
XIf compilation is succesful you must initialize the score file (just type
X'sokoban -c')
X
XThere is no manual page. All you have to know when you first play the game is
Xthe command '?'. This gives you one screenful of information.
X
XAfter you have solved all the given screens (this will take a while) you will
Xfind the game boring (sure you will). I hope there will be a lot of players who
Xwill think out some new screens.
XTo test your own screens copy them to the screen directory (with a new level
Xnumber <nn>) and type sokoban -<nn>.
X
XPLEASE DO SO AND POST NEW SCREENS TO THE NET.
XOTHERWISE IT GETS BORING !!!!!!!!!!!!!!!!!!!!
X
XComments are welcome.
X
X>From Canada or the US reply to ...!pyramid!tub!astbe!ber
X   (otherwise it would be expensive)
Xfrom elsewhere reply to ber@astbe
END_OF_FILE
if test 1552 -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'\" \(2005 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X Makefile                   1	
X README                     1	
X README.v2                  1	
X play.c                     1	
X readscreen.c               2	
X save.c                     1	
X score.c                    1	
X screen.1                   2	
X screen.10                  2	
X screen.11                  2	
X screen.12                  2	
X screen.13                  2	
X screen.14                  2	
X screen.15                  2	
X screen.16                  2	
X screen.17                  2	
X screen.18                  2	
X screen.19                  2	
X screen.2                   2	
X screen.20                  2	
X screen.21                  2	
X screen.22                  2	
X screen.23                  2	
X screen.24                  2	
X screen.25                  2	
X screen.26                  2	
X screen.27                  2	
X screen.28                  2	
X screen.29                  1	
X screen.3                   2	
X screen.30                  2	
X screen.31                  2	
X screen.32                  2	
X screen.33                  2	
X screen.34                  2	
X screen.35                  2	
X screen.36                  2	
X screen.37                  2	
X screen.38                  2	
X screen.39                  2	
X screen.4                   2	
X screen.40                  2	
X screen.41                  2	
X screen.42                  2	
X screen.43                  2	
X screen.44                  2	
X screen.45                  2	
X screen.46                  2	
X screen.47                  2	
X screen.48                  2	
X screen.49                  2	
X screen.5                   2	
X screen.50                  2	
X screen.6                   2	
X screen.7                   2	
X screen.8                   2	
X screen.9                   2	
X showscreen.c               1	
X sok.c                      1	
X sokoban.h                  1	
END_OF_FILE
if test 2005 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(477 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XCCOPT= -O
XOBJECTS= sok.o readscreen.o showscreen.o play.o save.o score.o
X
Xsokoban: $(OBJECTS)
X	cc $(CCOPT) -o sokoban $(OBJECTS) -lcurses -ltermcap
Xsok.o: sok.c sokoban.h
X	cc $(CCOPT) -c sok.c
X
Xreadscreen.o: readscreen.c sokoban.h
X	cc $(CCOPT) -c readscreen.c
X
Xshowscreen.o: showscreen.c sokoban.h
X	cc $(CCOPT) -c showscreen.c
X
Xplay.o: play.c sokoban.h
X	cc $(CCOPT) -c play.c
X
Xsave.o: save.c sokoban.h
X	cc $(CCOPT) -c save.c
X
Xscore.o: score.c sokoban.h
X	cc $(CCOPT) -c score.c
END_OF_FILE
if test 477 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README.v2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README.v2'\"
else
echo shar: Extracting \"'README.v2'\" \(1264 characters\)
sed "s/^X//" >'README.v2' <<'END_OF_FILE'
XThis is my second version of SOKOBAN.
X
XThe first thing I have to say is that I don't have the sources for SOKOBAN
Xunder MS-DOS. I believe that this program is copyrighted. I took only the
Xidea and the screens of the PC-version.
XI think that porting my version of SOKOBAN to the PC will not be very difficult
Xif you use the PC-Curses version which was on the net some months ago.
X
XI had a short mail talk with Norman Ramsey (...!allegra!princeton!nr) who wants 
Xto do the porting. He said that he will post his version if the work is done.
X
XSome people asked me whether it is possible to make a better looking screen.
XI added some extra definitions to the header file sokoban.h so that it is
Xpossible to alter the the characters that are used for the representation of
Xthe objects on the screen. You can also define wheter the object is displayed
Xin standout mode (invers) or not.
X
XThere is no helpfile anymore (sokoban.help in the first version). I
Xincluded the help file in showscreen.c and made a better help facility.
X
XThe score files from both versions are compatible so that you can go on with
Xthe game.
X
XAt last I added some new screens. I hope you enjoy them.
X
XIf you have already designed some new screens mail them to me. My netadress is
Xgiven in README.
END_OF_FILE
if test 1264 -ne `wc -c <'README.v2'`; then
    echo shar: \"'README.v2'\" unpacked with wrong size!
fi
# end of 'README.v2'
fi
if test -f 'play.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'play.c'\"
else
echo shar: Extracting \"'play.c'\" \(7208 characters\)
sed "s/^X//" >'play.c' <<'END_OF_FILE'
X#include <ctype.h>
X#include <curses.h>
X#include "sokoban.h"
X
X/* defining the types of move */
X#define MOVE 		1
X#define PUSH 		2
X#define SAVE 		3
X#define UNSAVE 		4
X#define STOREMOVE 	5
X#define STOREPUSH 	6
X
X/* defines for control characters */
X#define CNTL_L		'\014'
X#define CNTL_K		'\013'
X#define CNTL_H		'\010'
X#define CNTL_J		'\012'
X#define CNTL_R		'\022'
X#define CNTL_U		'\025'
X
Xextern char  map[MAXROW+1][MAXCOL+1];
Xextern short rows, cols, level, moves, pushes, savepack, packets;
Xextern short scorelevel, scoremoves, scorepushes;
Xextern POS   ppos;
X
Xstatic POS   tpos1,		   /* testpos1: 1 pos. over/under/left/right */
X             tpos2,		   /* testpos2: 2 pos.  "                    */
X             lastppos,		   /* the last player position (for undo)    */
X             lasttpos1, lasttpos2; /* last test positions (for undo)         */
Xstatic char lppc, ltp1c, ltp2c;    /* the char for the above pos. (for undo) */
Xstatic short action, lastaction;
X
X/** For the temporary save **/
Xstatic char  tmp_map[MAXROW+1][MAXCOL+1];
Xstatic short tmp_pushes, tmp_moves, tmp_savepack;
Xstatic POS   tmp_ppos;
X
Xshort play() {
X
X   short c;
X   short ret;
X   short undolock = 1;		/* locked for undo */
X
X   showscreen();
X   tmpsave();
X   ret = 0;
X   while( ret == 0) {
X      switch( (c = getch())) {
X	 case 'q':    /* quit the game 					*/
X	              ret = E_ENDGAME; 
X	              break;
X	 case 's':    /* save the games					*/
X		      if( (ret = savegame()) == 0)
X			 ret = E_SAVED;
X		      break;
X	 case '?':    /* show the help file				*/
X		      showhelp();
X		      showscreen();
X		      break;
X	 case CNTL_R: /* refresh the screen 				*/
X		      clear();
X		      showscreen();
X		      break;
X	 case 'c':    /* temporary save					*/
X		      tmpsave();
X		      break;
X	 case CNTL_U: /* reset to temporary save 			*/
X		      tmpreset();
X		      undolock = 1;
X		      showscreen();
X		      break;
X	 case 'U':    /* undo this level 				*/
X		      moves = pushes = 0;
X		      if( (ret = readscreen()) == 0) {
X		         showscreen();
X			 undolock = 1;
X		      }
X		      break;
X	 case 'u':    /* undo last move 				*/
X		      if( ! undolock) {
X		         undomove();
X		         undolock = 1;
X		      }
X		      break;
X	 case 'k':    /* up 						*/
X	 case 'K':    /* run up 					*/
X	 case CNTL_K: /* run up, stop before object 			*/
X	 case 'j':    /* down 						*/
X	 case 'J':    /* run down 					*/
X	 case CNTL_J: /* run down, stop before object 			*/
X	 case 'l':    /* right 						*/
X	 case 'L':    /* run right 					*/
X	 case CNTL_L: /* run right, stop before object 			*/
X	 case 'h':    /* left 						*/
X	 case 'H':    /* run left 					*/
X	 case CNTL_H: /* run left, stop before object 			*/
X		      do {
X		         if( (action = testmove( c)) != 0) {
X			    lastaction = action;
X		            lastppos.x = ppos.x; lastppos.y = ppos.y;
X		            lppc = map[ppos.x][ppos.y];
X		            lasttpos1.x = tpos1.x; lasttpos1.y = tpos1.y; 
X		            ltp1c = map[tpos1.x][tpos1.y];
X		            lasttpos2.x = tpos2.x; lasttpos2.y = tpos2.y; 
X		            ltp2c = map[tpos2.x][tpos2.y];
X		            domove( lastaction); 
X		            undolock = 0;
X		         }
X		      } while( (action != 0) && (! islower( c))
X			      && (packets != savepack));
X		      break;
X	 default:     helpmessage(); break;
X      }
X      if( (ret == 0) && (packets == savepack)) {
X	 scorelevel = level;
X	 scoremoves = moves;
X	 scorepushes = pushes;
X	 break;
X      }
X   }
X   return( ret);
X}
X
Xtestmove( action)
Xregister short action;
X{
X   register short ret;
X   register char  tc;
X   register short stop_at_object;
X
X   if( (stop_at_object = iscntrl( action))) action = action + 'A' - 1;
X   action = (isupper( action)) ? tolower( action) : action;
X   if( (action == 'k') || (action == 'j')) {
X      tpos1.x = (action == 'k') ? ppos.x-1 : ppos.x+1;
X      tpos2.x = (action == 'k') ? ppos.x-2 : ppos.x+2;
X      tpos1.y = tpos2.y = ppos.y;
X   }
X   else {
X      tpos1.y = (action == 'h') ? ppos.y-1 : ppos.y+1;
X      tpos2.y = (action == 'h') ? ppos.y-2 : ppos.y+2;
X      tpos1.x = tpos2.x = ppos.x;
X   }
X   tc = map[tpos1.x][tpos1.y];
X   if( (tc == packet.obj_intern) || (tc == save.obj_intern)) {
X      if( ! stop_at_object) {
X         if( map[tpos2.x][tpos2.y] == ground.obj_intern)
X            ret = (tc == save.obj_intern) ? UNSAVE : PUSH;
X         else if( map[tpos2.x][tpos2.y] == store.obj_intern)
X            ret = (tc == save.obj_intern) ? STOREPUSH : SAVE;
X         else ret = 0;
X      }
X      else ret = 0;
X   }
X   else if( tc == ground.obj_intern)
X      ret = MOVE;
X   else if( tc == store.obj_intern)
X      ret = STOREMOVE;
X   else ret = 0;
X   return( ret);
X}
X
Xdomove( moveaction) 
Xregister short moveaction;
X{
X   map[ppos.x][ppos.y] = (map[ppos.x][ppos.y] == player.obj_intern) 
X			       ? ground.obj_intern 
X			       : store.obj_intern;
X   switch( moveaction) {
X      case MOVE:      map[tpos1.x][tpos1.y] = player.obj_intern; 	break;
X      case STOREMOVE: map[tpos1.x][tpos1.y] = playerstore.obj_intern; 	break;
X      case PUSH:      map[tpos2.x][tpos2.y] = map[tpos1.x][tpos1.y];
X		      map[tpos1.x][tpos1.y] = player.obj_intern;	
X		      pushes++;						break;
X      case UNSAVE:    map[tpos2.x][tpos2.y] = packet.obj_intern;
X		      map[tpos1.x][tpos1.y] = playerstore.obj_intern;		
X		      pushes++; savepack--;			 	break;
X      case SAVE:      map[tpos2.x][tpos2.y] = save.obj_intern;
X		      map[tpos1.x][tpos1.y] = player.obj_intern;			
X		      savepack++; pushes++;				break;
X      case STOREPUSH: map[tpos2.x][tpos2.y] = save.obj_intern;
X		      map[tpos1.x][tpos1.y] = playerstore.obj_intern;		
X		      pushes++;						break;
X   }
X   moves++;
X   dispmoves(); disppushes(); dispsave();
X   mapchar( map[ppos.x][ppos.y], ppos.x, ppos.y);
X   mapchar( map[tpos1.x][tpos1.y], tpos1.x, tpos1.y);
X   mapchar( map[tpos2.x][tpos2.y], tpos2.x, tpos2.y);
X   move( MAXROW+1, 0);
X   refresh();
X   ppos.x = tpos1.x; ppos.y = tpos1.y;
X}
X
Xundomove() {
X
X   map[lastppos.x][lastppos.y] = lppc;
X   map[lasttpos1.x][lasttpos1.y] = ltp1c;
X   map[lasttpos2.x][lasttpos2.y] = ltp2c;
X   ppos.x = lastppos.x; ppos.y = lastppos.y;
X   switch( lastaction) {
X      case MOVE:      moves--;				break;
X      case STOREMOVE: moves--;				break;
X      case PUSH:      moves--; pushes--;		break;
X      case UNSAVE:    moves--; pushes--; savepack++;	break;
X      case SAVE:      moves--; pushes--; savepack--;	break;
X      case STOREPUSH: moves--; pushes--;		break;
X   }
X   dispmoves(); disppushes(); dispsave();
X   mapchar( map[ppos.x][ppos.y], ppos.x, ppos.y);
X   mapchar( map[lasttpos1.x][lasttpos1.y], lasttpos1.x, lasttpos1.y);
X   mapchar( map[lasttpos2.x][lasttpos2.y], lasttpos2.x, lasttpos2.y);
X   move( MAXROW+1, 0);
X   refresh();
X}
X
Xtmpsave() {
X
X   register short i, j;
X
X   for( i = 0; i < rows; i++) for( j = 0; j < cols; j++)
X      tmp_map[i][j] = map[i][j];
X   tmp_pushes = pushes;
X   tmp_moves = moves;
X   tmp_savepack = savepack;
X   tmp_ppos.x = ppos.x; tmp_ppos.y = ppos.y;
X}
X
Xtmpreset() {
X
X   register short i, j;
X
X   for( i = 0; i < rows; i++) for( j = 0; j < cols; j++)
X      map[i][j] = tmp_map[i][j];
X   pushes = tmp_pushes;
X   moves = tmp_moves;
X   savepack = tmp_savepack;
X   ppos.x = tmp_ppos.x; ppos.y = tmp_ppos.y;
X}
END_OF_FILE
if test 7208 -ne `wc -c <'play.c'`; then
    echo shar: \"'play.c'\" unpacked with wrong size!
fi
# end of 'play.c'
fi
if test -f 'save.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'save.c'\"
else
echo shar: Extracting \"'save.c'\" \(3668 characters\)
sed "s/^X//" >'save.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X#include "sokoban.h"
X
Xextern char  *malloc();
Xextern FILE  *fopen();
X
Xextern char  *username;
Xextern char  map[MAXROW+1][MAXCOL+1];
Xextern short level, moves, pushes, packets, savepack, rows, cols;
Xextern short scoring;
Xextern POS   ppos;
X
Xstatic long        savedbn;
Xstatic char        *sfname;
Xstatic FILE        *savefile;
Xstatic struct stat sfstat;
X
Xshort savegame() {
X
X   short ret = 0;
X
X   signal( SIGINT, SIG_IGN);
X   sfname = malloc( strlen( SAVEPATH) + strlen( username) + 5);
X   sprintf( sfname, "%s/%s.sav", SAVEPATH, username);
X   if( (savefile = fopen( sfname, "w")) == NULL)
X      ret = E_FOPENSAVE;
X   else {
X      savedbn = fileno( savefile);
X      if( write( savedbn, &(map[0][0]), MAXROW*MAXCOL) != MAXROW*MAXCOL)
X	 ret = E_WRITESAVE;
X      else if( write( savedbn, &ppos, sizeof( POS)) != sizeof( POS))     
X	 ret = E_WRITESAVE;
X      else if( write( savedbn, &scoring, 2) != 2)  ret = E_WRITESAVE;
X      else if( write( savedbn, &level, 2) != 2)    ret = E_WRITESAVE;
X      else if( write( savedbn, &moves, 2) != 2)    ret = E_WRITESAVE;
X      else if( write( savedbn, &pushes, 2) != 2)   ret = E_WRITESAVE;
X      else if( write( savedbn, &packets, 2) != 2)  ret = E_WRITESAVE;
X      else if( write( savedbn, &savepack, 2) != 2) ret = E_WRITESAVE;
X      else if( write( savedbn, &rows, 2) != 2)     ret = E_WRITESAVE;
X      else if( write( savedbn, &cols, 2) != 2)     ret = E_WRITESAVE;
X      else {
X	 fclose( savefile);
X	 if( stat( sfname, &sfstat) != 0) ret = E_STATSAVE;
X	 else if( (savefile = fopen( sfname, "a")) == NULL)
X            ret = E_FOPENSAVE;
X         else {
X	    if( write( savedbn, &sfstat, sizeof( sfstat)) != sizeof( sfstat))
X	       ret = E_WRITESAVE;
X	    fclose( savefile);
X	 }
X      }
X   }
X   if( (ret == E_WRITESAVE) || (ret == E_STATSAVE)) unlink( sfname);
X   signal( SIGINT, SIG_DFL);
X
X   return( ret);
X}
X
Xshort restoregame() {
X
X   short ret = 0;
X   struct stat oldsfstat;
X
X   signal( SIGINT, SIG_IGN);
X   sfname = malloc( strlen( SAVEPATH) + strlen( username) + 5);
X   sprintf( sfname, "%s/%s.sav", SAVEPATH, username);
X   if( stat( sfname, &oldsfstat) < -1) 
X      ret = E_NOSAVEFILE;
X   else {
X      if( (savefile = fopen( sfname, "r")) == NULL)
X	 ret = E_FOPENSAVE;
X      else {
X         savedbn = fileno( savefile);
X         if( read( savedbn, &(map[0][0]), MAXROW*MAXCOL) != MAXROW*MAXCOL)
X	    ret = E_READSAVE;
X         else if( read( savedbn, &ppos, sizeof( POS)) != sizeof( POS))     
X	    ret = E_READSAVE;
X         else if( read( savedbn, &scoring, 2) != 2)  ret = E_READSAVE;
X         else if( read( savedbn, &level, 2) != 2)    ret = E_READSAVE;
X         else if( read( savedbn, &moves, 2) != 2)    ret = E_READSAVE;
X         else if( read( savedbn, &pushes, 2) != 2)   ret = E_READSAVE;
X         else if( read( savedbn, &packets, 2) != 2)  ret = E_READSAVE;
X         else if( read( savedbn, &savepack, 2) != 2) ret = E_READSAVE;
X         else if( read( savedbn, &rows, 2) != 2)     ret = E_READSAVE;
X         else if( read( savedbn, &cols, 2) != 2)     ret = E_READSAVE;
X	 else if( read( savedbn, &sfstat, sizeof( sfstat)) != sizeof( sfstat))
X	    ret = E_READSAVE;
X	 else if( (sfstat.st_dev != oldsfstat.st_dev) ||
X                  (sfstat.st_ino != oldsfstat.st_ino) ||
X                  (sfstat.st_nlink != oldsfstat.st_nlink) ||
X                  (sfstat.st_uid != oldsfstat.st_uid) ||
X                  (sfstat.st_gid != oldsfstat.st_gid) ||
X                  (sfstat.st_mtime != oldsfstat.st_mtime))
X            ret = E_ALTERSAVE;
X      }
X      unlink( sfname);
X   }
X   signal( SIGINT, SIG_DFL);
X   return( ret);
X}
END_OF_FILE
if test 3668 -ne `wc -c <'save.c'`; then
    echo shar: \"'save.c'\" unpacked with wrong size!
fi
# end of 'save.c'
fi
if test -f 'score.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'score.c'\"
else
echo shar: Extracting \"'score.c'\" \(5071 characters\)
sed "s/^X//" >'score.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <signal.h>
X#include "sokoban.h"
X
Xextern FILE *fopen();
X
Xextern char  *username;
Xextern short scorelevel, scoremoves, scorepushes;
X
Xstatic short scoreentries;
Xstatic struct {
X   char user[MAXUSERNAME];
X   short lv, mv, ps;
X} scoretable[MAXSCOREENTRIES];
X
Xstatic FILE *scorefile;
Xstatic long sfdbn;
X
Xshort outputscore() {
X
X   short ret;
X
X   while( creat( LOCKFILE, 0666) < 0);	/* lock the score file */
X   if( (ret = readscore()) == 0)
X      showscore();
X   unlink( LOCKFILE);
X   return( (ret == 0) ? E_ENDGAME : ret);
X}
X
Xshort makenewscore() {
X
X   short ret = 0;
X
X   while( creat( LOCKFILE, 0666) < 0) ;
X   scoreentries = 0;
X   if( (scorefile = fopen( SCOREFILE, "w")) == NULL)
X      ret = E_FOPENSCORE;
X   else {
X      sfdbn = fileno( scorefile);
X      if( write( sfdbn, &scoreentries, 2) != 2) ret = E_WRITESCORE;
X      fclose( scorefile);
X   }
X   unlink( LOCKFILE);
X   return( (ret == 0) ? E_ENDGAME : ret);
X}
X
Xshort getuserlevel( lv)
Xshort *lv;
X{
X   short ret = 0, pos;
X
X   while( creat( LOCKFILE, 0666) < 0);
X   if( (scorefile = fopen( SCOREFILE, "r")) == NULL)
X      ret = E_FOPENSCORE;
X   else {
X      if( (ret = readscore()) == 0)
X	 *lv = ( (pos = finduser()) > -1) ? scoretable[pos].lv+1 : 1;
X   }
X   unlink( LOCKFILE);
X   return( ret);
X}
X
Xshort score() {
X   
X   short ret;
X
X   while( creat( LOCKFILE, 0666) < 0);	/* lock the score file */
X   if( (ret = readscore()) == 0)
X      if( (ret = makescore()) == 0)
X	 if( (ret = writescore()) == 0)
X	    showscore();
X   unlink( LOCKFILE);
X   return( (ret == 0) ? E_ENDGAME : ret);
X}
X
Xreadscore() {
X
X   short ret = 0;
X   long tmp;
X
X   if( (scorefile = fopen( SCOREFILE, "r")) == NULL)
X      ret = E_FOPENSCORE;
X   else {
X      sfdbn = fileno( scorefile);
X      if( read( sfdbn, &scoreentries, 2) != 2) ret = E_READSCORE;
X      else {
X	 tmp = scoreentries * sizeof( scoretable[0]);
X	 if( read( sfdbn, &(scoretable[0]), tmp) != tmp) ret = E_READSCORE;
X      }
X      fclose( scorefile);
X   }
X   return( ret);
X}
X
Xmakescore() {
X
X   short ret = 0, pos, i, build = 1, insert;
X
X   if( (pos = finduser()) > -1) {	/* user already in score file */
X      insert =    (scorelevel > scoretable[pos].lv)
X	       || ( (scorelevel == scoretable[pos].lv) &&
X                    (scoremoves < scoretable[pos].mv)
X		  )
X	       || ( (scorelevel == scoretable[pos].lv) &&
X		    (scoremoves == scoretable[pos].mv) &&
X		    (scorepushes < scoretable[pos].ps)
X		  );
X      if( insert) { 			/* delete existing entry */
X	 for( i = pos; i < scoreentries-1; i++)
X	    cp_entry( i, i+1);
X	 scoreentries--;
X      }
X      else build = 0;
X   }
X   else if( scoreentries == MAXSCOREENTRIES)
X      ret = E_TOMUCHSE;
X   if( (ret == 0) && build) {
X      pos = findpos();			/* find the new score position */
X      if( pos > -1) {			/* score table not empty */
X	 for( i = scoreentries; i > pos; i--)
X	    cp_entry( i, i-1);
X      }
X      else pos = scoreentries;
X
X      strcpy( scoretable[pos].user, username);
X      scoretable[pos].lv = scorelevel;
X      scoretable[pos].mv = scoremoves;
X      scoretable[pos].ps = scorepushes;
X      scoreentries++;
X   }
X   return( ret);
X}
X
Xfinduser() {
X
X   short i, found = 0;
X
X   for( i = 0; (i < scoreentries) && (! found); i++)
X      found = (strcmp( scoretable[i].user, username) == 0);
X   return( (found) ? i-1 : -1);
X}
X
Xfindpos() {
X 
X   short i, found = 0;
X
X   for( i = 0; (i < scoreentries) && (! found); i++)
X      found =    (scorelevel > scoretable[i].lv)
X	      || ( (scorelevel == scoretable[i].lv) &&
X                   (scoremoves < scoretable[i].mv)
X		 )
X	      || ( (scorelevel == scoretable[i].lv) &&
X		   (scoremoves == scoretable[i].mv) &&
X		   (scorepushes < scoretable[i].ps)
X		 );
X   return( (found) ? i-1 : -1);
X}
X
Xwritescore() {
X
X   short ret = 0;
X   long tmp;
X
X   if( (scorefile = fopen( SCOREFILE, "w")) == NULL)
X      ret = E_FOPENSCORE;
X   else {
X      sfdbn = fileno( scorefile);
X      if( write( sfdbn, &scoreentries, 2) != 2) ret = E_WRITESCORE;
X      else {
X	 tmp = scoreentries * sizeof( scoretable[0]);
X	 if( write( sfdbn, &(scoretable[0]), tmp) != tmp) ret = E_WRITESCORE;
X      }
X      fclose( scorefile);
X   }
X   return( ret);
X}
X
Xshowscore() {
X
X   register short lastlv = 0, lastmv = 0, lastps = 0, i;
X
X   fprintf( stdout, "Rank        User     Level     Moves    Pushes\n");
X   fprintf( stdout, "==============================================\n");
X   for( i = 0; i < scoreentries; i++) {
X      if( (scoretable[i].lv == lastlv)&& 
X	  (scoretable[i].mv == lastmv) && 
X	  (scoretable[i].ps == lastps))
X	 fprintf( stdout, "      ");
X      else {
X         lastlv = scoretable[i].lv;
X         lastmv = scoretable[i].mv;
X         lastps = scoretable[i].ps;
X         fprintf( stdout, "%4d  ", i+1);
X      }
X      fprintf( stdout, "%10s  %8d  %8d  %8d\n", scoretable[i].user, 
X		scoretable[i].lv, scoretable[i].mv, scoretable[i].ps);
X   }
X}
X
Xcp_entry( i1, i2)
Xregister short i1, i2;
X{
X   strcpy( scoretable[i1].user, scoretable[i2].user);
X   scoretable[i1].lv = scoretable[i2].lv;
X   scoretable[i1].mv = scoretable[i2].mv;
X   scoretable[i1].ps = scoretable[i2].ps;
X}
END_OF_FILE
if test 5071 -ne `wc -c <'score.c'`; then
    echo shar: \"'score.c'\" unpacked with wrong size!
fi
# end of 'score.c'
fi
if test -f 'screen.29' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'screen.29'\"
else
echo shar: Extracting \"'screen.29'\" \(228 characters\)
sed "s/^X//" >'screen.29' <<'END_OF_FILE'
X#####
X#   ##
X# $  #########
X## # #       ######
X## #   $#$#@  #   #
X#  #      $ #   $ #
X#  ### ######### ##
X#  ## ..*..... # ##
X## ## *.*..*.* # ##
X# $########## ##$ #
X#  $   $  $    $  #
X#  #   #   #   #  #
X###################
END_OF_FILE
if test 228 -ne `wc -c <'screen.29'`; then
    echo shar: \"'screen.29'\" unpacked with wrong size!
fi
# end of 'screen.29'
fi
if test -f 'showscreen.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'showscreen.c'\"
else
echo shar: Extracting \"'showscreen.c'\" \(5637 characters\)
sed "s/^X//" >'showscreen.c' <<'END_OF_FILE'
X#include <curses.h>
X#include "sokoban.h"
X
Xextern short rows, cols, level, moves, pushes, packets, savepack;
Xextern char  map[MAXROW+1][MAXCOL+1];
X
Xshowscreen() {
X
X   register short i, j;
X
X   move( 0, 0); clrtobot();
X   for( i = 0; i < rows; i++)
X      for( j = 0; map[i][j] != '\0'; j++)
X         mapchar( map[i][j], i, j);
X   move( MAXROW, 0);
X   printw( "Level:      Packets:      Saved:      Moves:       Pushes:");
X   displevel();
X   disppackets();
X   dispsave();
X   dispmoves();
X   disppushes();
X   move( MAXROW+2,0);
X   refresh();
X}
X
Xmapchar( c, i, j) 
Xregister char c; 
Xregister short i, j;
X{
X   OBJECT *obj, *get_obj_adr();
X   register short offset_row = (MAXROW - rows) / 2;
X   register short offset_col = MAXCOL - cols;
X
X   obj = get_obj_adr( c);
X
X   if( obj->invers) standout();
X   move( i + offset_row, 2*j + offset_col); 
X   printw( "%c%c", obj -> obj_display, obj -> obj_display);
X   if( obj->invers) standend();
X}
X
XOBJECT *get_obj_adr( c)
Xregister char c;
X{
X   register OBJECT *ret;
X
X   if(      c == player.obj_intern)		ret = &player;
X   else if( c == playerstore.obj_intern)	ret = &playerstore;
X   else if( c == store.obj_intern)		ret = &store;
X   else if( c == save.obj_intern)		ret = &save;
X   else if( c == packet.obj_intern)		ret = &packet;
X   else if( c == wall.obj_intern)		ret = &wall;
X   else if( c == ground.obj_intern)		ret = &ground;
X   else                                         ret = &ground;
X
X   return( ret);
X}
X
X
Xdisplevel() { 
X   move( MAXROW, 7); printw( "%3d", level); 
X}
X   
Xdisppackets() { 
X   move( MAXROW, 21); printw( "%3d", packets); 
X}
X   
Xdispsave() { 
X   move( MAXROW, 33); printw( "%3d", savepack); 
X}
X   
Xdispmoves() { 
X   move( MAXROW, 45); printw( "%5d", moves); 
X}
X      
Xdisppushes() { 
X   move( MAXROW, 59); printw( "%5d", pushes); 
X}
X
Xhelpmessage() {
X
X   move( MAXROW+2, 0); 
X   printw( "Press ? for help.%c", '\007');
X   refresh();
X   raw();			/* no input allowed while sleeping */
X   sleep( 2);
X   move( MAXROW+2, 0); deleteln();
X   refresh();
X   noraw();				/* end raw mode */
X}
X
Xstatic char *helppages[] = { /* be sure that there are max 9 lines per page */
X   "The problem is to push packets to",
X   "saving positions by moving around",
X   "and  pushing only one packet at a",
X   "        time if possible.        ",
X   "                                 ",
X   "                                 ",
X   "                                 ",
X   "                                 ",
X   "                                 ",
X   NULL,					/* end of page */
X   "Moving: You can move by using    ",
X   "           the vi-keys hjkl.     ",
X   "                                 ",
X   "              left right up down ",
X   "  Move/Push     h    l    k   j  ",
X   "  Run/Push      H    L    K   J  ",
X   "  Run only     ^H   ^L   ^K  ^J  ",
X   "                                 ",
X   "                                 ",
X   NULL,					/* end of page */
X   "Other commands:                  ",
X   "   c:  temporary save            ",
X   "   q:  quit                      ",
X   "  ^R:  refresh the screen        ",
X   "   s:  save the game             ",
X   "   u:  undo last move/push       ",
X   "   U:  undo all                  ",
X   "  ^U:  reset to temp save        ",
X   "   ?:  this help scree           ",
X   NULL,					/* end of page */
X   "Characters on screen are:        ",
X   "                                 ",
X   "  %@  player                     ",
X   "  %+  player on saving position  ",
X   "  %.  saving position for packet ",
X   "  %$  packet                     ",
X   "  %*  saved packet               ",
X   "  %#  wall                       ",
X   "                                 ",
X   NULL,				/* end of page */
X   "If you set a temporary  save, you",
X   "need not  undo  all when you  get",
X   "stucked. Just reset to this save.",
X   "                                 ",
X   "A temporary save is automatically",
X   "made at the start.",
X   "                                 ",
X   "                                 ",
X   "                                 ",
X   NULL,					/* end of page */
X   NULL						/* total end */
X};
X
Xstatic char *title[] = {
X   "          S O K O B A N          ",
X   "---------------------------------"
X};
X
Xstatic char *helphelp[] = {
X   "   (Press return to exit help,   ",
X   "    any other key to continue)   "
X};
X
X#define HELPROWS	16
X#define HELPCOLS	37
X
Xshowhelp() {
X
X   register short line, i;
X   short goon = 1;
X   WINDOW *win, *makehelpwin();
X
X   win = makehelpwin();
X   for( i = 0, line = 2; goon; i++, line++) {
X      if( helppages[i] != NULL) {
X	 wmove( win, line+1, 2);
X	 printhelpline( win, helppages[i]);
X      }
X      else {
X	 wmove( win, HELPROWS-1, 0);
X	 wrefresh( win);
X	 if( (goon = (wgetch( win) != '\n'))) {
X	    line = 1;
X	    if( helppages[i+1] == NULL) i = -1;
X	 }
X      }
X   }
X   werase( win);
X   wrefresh( win);
X   delwin( win);
X}
X
XWINDOW *makehelpwin() {
X
X   WINDOW *win, *newwin();
X
X   win = newwin( HELPROWS, HELPCOLS, 2, 0);
X   box( win, '|', '-');
X   wmove( win, 1, 2);
X   wprintw( win, "%s", title[0]);
X   wmove( win, 2, 2);
X   wprintw( win, "%s", title[1]);
X   wmove( win, HELPROWS-3, 2);
X   wprintw( win, "%s", helphelp[0]);
X   wmove( win, HELPROWS-2, 2);
X   wprintw( win, "%s", helphelp[1]);
X
X   return( win);
X}
X
Xprinthelpline( win, line)
XWINDOW *win;
Xchar *line;
X{
X   OBJECT *obj, *get_obj_adr();
X
X   for( ; *line != '\0'; line++) {
X      if( *line == '%') {
X	 ++line;
X	 obj = get_obj_adr( *line);
X         if( obj -> invers) wstandout( win);
X         waddch( win, obj -> obj_display); waddch( win, obj -> obj_display);
X         if( obj -> invers) wstandend( win);
X      }
X      else waddch( win, *line);
X   }
X}
END_OF_FILE
if test 5637 -ne `wc -c <'showscreen.c'`; then
    echo shar: \"'showscreen.c'\" unpacked with wrong size!
fi
# end of 'showscreen.c'
fi
if test -f 'sok.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sok.c'\"
else
echo shar: Extracting \"'sok.c'\" \(4818 characters\)
sed "s/^X//" >'sok.c' <<'END_OF_FILE'
X#include <curses.h>
X#include "sokoban.h"
X
Xextern char  *strrchr(), *getlogin(), *getpass();
Xextern short readscreen(), play(), outputscore(), getuserlevel(),
X	     makenewscore(), restoregame(), score();
X
Xshort scoring = 1;
Xshort level, packets, savepack, moves, pushes, rows, cols;
Xshort scorelevel, scoremoves, scorepushes;
Xchar  map[MAXROW+1][MAXCOL+1];
XPOS   ppos;
Xchar  *username, *prgname;
X
Xstatic short optshowscore = 0, 
X	     optmakescore = 0, 
X             optrestore = 0, 
X	     optlevel = 0; 
Xstatic short superuser = 0;
X
Xstatic short userlevel;
X
Xmain( argc, argv) 
Xshort argc; 
Xchar *argv[];
X{
X   short ret, ret2;
X
X   scorelevel = 0;
X   moves = pushes = packets = savepack = 0;
X   if( (prgname = strrchr( argv[0], '/')) == NULL)
X      prgname = argv[0];
X   else prgname++;
X   if( (username = getlogin()) == NULL)
X      ret = E_NOUSER;
X   else {
X      superuser = (strcmp( username, SUPERUSER) == 0);
X      if( (ret = checkcmdline( argc, argv)) == 0) {
X         if( optshowscore)
X	    ret = outputscore();
X         else if( optmakescore) {
X	    if( superuser) {
X	       if( (ret = getpassword()) == 0)
X	          ret = makenewscore();
X	    }
X	    else ret = E_NOSUPER;
X	 }
X	 else if( optrestore) {
X	    ret = restoregame();
X	 }
X         else if( (ret = getuserlevel( &userlevel)) == 0) {
X            if( optlevel > 0) {
X	       if( superuser) {
X	          level = optlevel;
X		  scoring = 0;
X	       }
X	       else if( userlevel < optlevel)
X	          ret = E_LEVELTOOHIGH;
X	       else level = optlevel;
X	    }
X	    else level = userlevel;
X         }
X      }
X   }
X   if( ret == 0)
X      ret = gameloop();
X   errmess( ret);
X   if( scorelevel && scoring) {
X      ret2 = score();
X      errmess( ret2);
X   }
X   exit( ret);
X}
X
Xcheckcmdline( argc, argv) 
Xshort argc; 
Xchar *argv[];
X{
X   short ret = 0;
X
X   if( argc > 1)
X      if( (argc == 2) && (argv[1][0] == '-')) {
X	 if( (argv[1][1] == 's') && (argv[1][2] == '\0'))
X	    optshowscore = 1;
X	 else if( (argv[1][1] == 'c') && (argv[1][2] == '\0'))
X	    optmakescore = 1;
X	 else if( (argv[1][1] == 'r') && (argv[1][2] == '\0'))
X	    optrestore = 1;
X	 else if( (optlevel = atoi( &(argv[1][1]))) == 0)
X	    ret = E_USAGE;
X      }
X      else ret = E_USAGE;
X   return( ret);
X}
X
Xgameloop() {
X
X   short ret = 0;
X
X   initscr(); crmode(); noecho();
X   if( ! optrestore) ret = readscreen();
X   while( ret == 0) {
X      if( (ret = play()) == 0) {
X         level++;
X         moves = pushes = packets = savepack = 0;
X         ret = readscreen();
X      }
X   }
X   clear(); refresh(); 
X   nocrmode(); echo(); endwin();
X   return( ret);
X}
X
Xgetpassword() {
X
X   return( (strcmp(getpass("Password: "), PASSWORD) == 0) ? 0 : E_ILLPASSWORD);
X}
X
Xchar *message[] = {
X   "illegal error number",
X   "cannot open screen file",
X   "more than one player position in screen file",
X   "illegal char in screen file",
X   "no player position in screenfile",
X   "too much rows in screen file",
X   "too much columns in screenfile",
X   "quit the game",
X   NULL,			/* errmessage deleted */
X   "cannot get your username",
X   "cannot open savefile",
X   "error writing to savefile",
X   "cannot stat savefile",
X   "error reading savefile",
X   "cannot restore, your savefile has been altered",
X   "game saved",
X   "too much users in score table",
X   "cannot open score file",
X   "error reading scorefile",
X   "error writing scorefile",
X   "illegal command line syntax",
X   "illegal password",
X   "level number too big in command line",
X   "only superuser is allowed to make a new score table",
X   "cannot find file to restore"
X};
X
Xerrmess( ret) 
Xregister short ret;
X{
X   if( ret != E_ENDGAME) {
X      fprintf( stderr, "%s: ", prgname);
X      switch( ret) {
X         case E_FOPENSCREEN: case E_PLAYPOS1:   case E_ILLCHAR: 
X	 case E_PLAYPOS2:    case E_TOMUCHROWS: case E_TOMUCHCOLS: 
X	 case E_ENDGAME:     case E_NOUSER:      
X	 case E_FOPENSAVE:   case E_WRITESAVE:  case E_STATSAVE:    
X	 case E_READSAVE:    case E_ALTERSAVE:  case E_SAVED:       
X	 case E_TOMUCHSE:    case E_FOPENSCORE: case E_READSCORE: 
X	 case E_WRITESCORE:  case E_USAGE:	case E_ILLPASSWORD:
X	 case E_LEVELTOOHIGH: case E_NOSUPER:	case E_NOSAVEFILE:
X			     fprintf( stderr, "%s\n", message[ret]);
X                             break;
X         default:            fprintf( stderr, "%s\n", message[0]);
X                             break;
X      }
X      if( ret == E_USAGE) usage();
X   }
X}
X
Xstatic char *usagestr[] = {
X   "           -c:    create new score table (superuser only)\n",
X   "           -r:    restore saved game\n",
X   "           -s:    show score table\n",
X   "           -<nn>: play this level (<nn> must be greater 0)\n",
X   NULL
X};
X
Xusage() {
X
X   register short i;
X
X   fprintf( stderr, "Usage: %s [-{s|c|r|<nn>}]\n\n", prgname);
X   for( i = 0; usagestr[i] != NULL; i++)
X      fprintf( stderr, "%s", usagestr[i]);
X}
END_OF_FILE
if test 4818 -ne `wc -c <'sok.c'`; then
    echo shar: \"'sok.c'\" unpacked with wrong size!
fi
# end of 'sok.c'
fi
if test -f 'sokoban.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sokoban.h'\"
else
echo shar: Extracting \"'sokoban.h'\" \(2949 characters\)
sed "s/^X//" >'sokoban.h' <<'END_OF_FILE'
X/***********************************************************************
X   You may wish to alter the following directory paths
X***********************************************************************/
X/**/
X/* SCREENPATH: the name of the directioy where the screen file are held */
X/**/
X#define SCREENPATH 	"/usr/games/lib/sokoban/screens"
X
X/**/
X/* SAVEPATH: the name of the path where save files are held */
X/*           Attention: Be sure that there are no other files with */
X/*                      the name <username>.sav                    */
X/**/
X#define SAVEPATH	"/usr/games/lib/sokoban"
X
X/**/
X/* LOCKPATH: temporary file which is created to ensure that no users */
X/*           work with the scorefile at the same time                */
X/**/
X#define LOCKFILE	"/tmp/sok.lock"
X
X/**/
X/* SCOREFILE: the full pathname of the score file */
X/**/
X#define SCOREFILE	"/usr/games/lib/sokoban/sok.score"
X
X/**/
X/* MAXUSERNAME: defines the maximum length of a system's user name */
X/**/
X#define MAXUSERNAME	10
X
X/**/
X/* MAXSCOREENTRIES: defines the maximum numner of entries in the scoretable */
X/**/
X#define MAXSCOREENTRIES	50
X
X/**/
X/* SUPERUSER: defines the name of the game superuser */
X/**/
X#define SUPERUSER "root"
X
X/**/
X/* PASSWORD: defines the password necessary for creating a new score file */
X/**/
X#define PASSWORD "nabokos"
X
X/**/
X/* OBJECT: this typedef is used for internal and external representation */
X/*         of objects                                                    */
X/**/
Xtypedef struct {
X   char obj_intern;	/* internal representation of the object */
X   char obj_display;	/* display char for the object		 */
X   short invers;	/* if set to 1 the object will be shown invers */
X} OBJECT;
X
X/**/
X/* You can now alter the definitions below.
X/* Attention: Do not alter `obj_intern'. This would cause an error */
X/*            when reading the screenfiles                         */
X/**/
Xstatic OBJECT 
X   player = 	 { '@', '@', 0 },
X   playerstore = { '+', '@', 1 },
X   store = 	 { '.', '.', 0 },
X   packet = 	 { '$', '$', 0 },
X   save = 	 { '*', '$', 1 },
X   ground = 	 { ' ', ' ', 0 },
X   wall = 	 { '#', ' ', 1 };
X
X/*************************************************************************
X********************** DO NOT CHANGE BELOW THIS LINE *********************
X*************************************************************************/
X#define MAXROW		20
X#define MAXCOL		40
X
Xtypedef struct {
X   short x, y;
X} POS;
X
X#define E_FOPENSCREEN	1
X#define E_PLAYPOS1	2
X#define E_ILLCHAR	3
X#define E_PLAYPOS2	4
X#define E_TOMUCHROWS	5
X#define E_TOMUCHCOLS	6
X#define E_ENDGAME	7
X#define E_NOUSER	9
X#define E_FOPENSAVE	10
X#define E_WRITESAVE	11
X#define E_STATSAVE	12
X#define E_READSAVE	13
X#define E_ALTERSAVE	14
X#define E_SAVED		15
X#define E_TOMUCHSE	16
X#define E_FOPENSCORE	17
X#define E_READSCORE	18
X#define E_WRITESCORE	19
X#define E_USAGE		20
X#define E_ILLPASSWORD	21
X#define E_LEVELTOOHIGH	22
X#define E_NOSUPER	23
X#define E_NOSAVEFILE	24
END_OF_FILE
if test 2949 -ne `wc -c <'sokoban.h'`; then
    echo shar: \"'sokoban.h'\" unpacked with wrong size!
fi
# end of 'sokoban.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