Subject: v06i016: tetris - popular game of dropping blocks, Part01/02
From: [email-masked]
Newsgroups: comp.sources.games

Submitted-by: Martin Heidegger <[email-masked]>
Posting-number: Volume 6, Issue 16
Archive-name: tetris/Part01

	[Just after I posted tetrix (the previous article), this showed up
	 in my mailbox. It is a different implementation of the same game
	 called tetris, instead of tetrix (anyone know the correct spelling?).
	 While the previous version was System V dependent, this one is
	 4.2/4.3 BSD.  -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 csr.c define_shapes.c end_game.c
#   init_tetris.c main.c print_shape.c process_input.c
# Wrapped by billr@saab on Tue Feb 28 12:49:58 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'\" \(2308 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X	Tetris: the first incarnation
X
X	I wrote this as a way to learn unix, and it shows. I am
Xreleasing this on a limited basis until I can get the bugs worked
Xout. The game looks good, and is playable, addictive even, but the
Xcode is horrendous.  I don't want to go into it but there are
Xsections of the program that are 30 line if statements.  I realised
Xafter finishing the program (more or less finishing it anyways)
Xthat there is a much better way to implement the moving of blocks
Xand collision detection.  However, the code is so ugly that I am
Xnot going to do it until possibly spring break.
X
XYou have been warned.
X
X	I have successfully compiled and run tetris on vaxen running
X4.3 BSD, ISI optimum V's runnning 4.2 BSD, and Sun 3/280's, 3/160's,
X4's running sun OS 4.0 and 4.01.  If you are on Xenix, SYSV, or
Xanything that is not close to BSD do yourself a favor and delete
Xthis code now!!!.
X
X	When I wrote this I used a local cursor package that is fast but
Xnot portable to systems other than BSDish Unixes. This cursor package is
Xincluded and is really a software system unto itself. It is fast, small, and
Xeasy to use. It is an ideal option to curses. To use it, you only need the
Xfiles csr.c and csr.h. Credit goes to chuck peterson ([email-masked]) for
Xthis handy package. The one problem with it, is that you will get 
Xa two line type conflict on compilation. This is something that I have
Xignored up till now. I suspect it is easy to fix, but I have not bothered.
X
X	When I first wrote this I had no knowledge of how to make
Xcode portable, so if you patch the code to run on another system
XI would REALLY appreciate your input and code. I also used tabstops
Xof 4 in vi, this is before I realized what a horrible thing this
Xis to do. To make things easier just set your EXINIT environment
Xvariable to "set ts=4 sw=4" when looking at the code.
X
X	There are some known bugs, look in the man page for them. I 
Xam busy so I may not get around to them for a while. Please pass any
Xnew bugs you find onto me.
X
X	I have lots of ideas for this game, but I have difficulty justifing
Xspending any time on the game. If you need to know the innards of the program
Xbecause you want to add on to it (or preferably, rewrite it) just mail me.
X
X
X	adam margulies
X	[email-masked]
X	{...}!ucbvax!ucscc!ssyx!vespa
END_OF_FILE
if test 2308 -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'\" \(1026 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X FILES                      2	
X MANIFEST                   1	
X Makefile                   2	
X README                     1	
X check_block.c              2	
X check_horiz.c              2	
X csr.c                      1	
X csr.h                      2	
X cursive.c                  2	
X define_shapes.c            1	
X display_high.c             2	
X draw_shadow.c              2	
X drop_block.c               2	
X end_game.c                 1	
X erase_horiz.c              2	
X get_level.c                2	
X help.tetris                2	
X init_tetris.c              1	
X main.c                     1	
X print_shape.c              1	
X process_input.c            1	
X redefine.c                 2	
X save_game.c                2	
X score.c                    2	
X score.tetris               2	
X set_level.c                2	
X setup_next.c               2	
X tetris.h                   2	
X tetris.man                 2	
X useful.c                   2	
END_OF_FILE
if test 1026 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'csr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'csr.c'\"
else
echo shar: Extracting \"'csr.c'\" \(6750 characters\)
sed "s/^X//" >'csr.c' <<'END_OF_FILE'
X/*
X * multi-trek: csr.c			1/5/86 Written by Chuck Peterson,
X * U.C. Santa Cruz There are two char arrays representing the screen. 
X * Window0 is the array which has what is currently on the terminal, and the
X * future screen window1[] is the array which all updates are done to with
X * the routines mvaddch(), mvaddstr(), move(), printc(), and clear().
X * Csr_draw() is passed coordinates bounding the box region of the future
X * screen which is to be transfered to the terminal. 
X *
X * BUGS: tabs, newlines, and control characters on the window arrays will screw
X * everything up. 
X *
X * init_csr()            -- initialize the whole thing
X * resetty()             -- reset term modes to like before init_csr()
X * mvaddch(y,x,ch)       -- add char to future screen
X * mvaddstr(y,x,ch)      -- add string to future screen
X * csr_draw(y1,x1,y2,x2) -- make current screen look like future screen in
X *                          the square bounded by the two coords
X * move(y,x)             -- move to current location in future window
X * printc(fmt, args)     -- printf into future screen @ current location
X * clear(y1,x1,y2,x2)    -- clear a box in the future screen 
X *
X * For raw cursor movement and clear screen: csr(y,x) cls() 
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include "csr.h"
X
X#define reg register
X#define MASK(sig)		(1 << ((sig) - 1))
X#define SIGHOLD(signo)		(sigblock(MASK(signo)))
X#define SIGRELSE(signo)		(sigsetmask(sigblock(0) &~ MASK(signo)))
X
Xchar	obuf[BUFSIZ];
Xchar	nowrapping;
X
X/* VARARGS */
Xextern ioctl();
X
Xinit_csr()
X{
X    static char     bp[1024];
X    static char     buffer[200];
X    char           *area = buffer;
X    char           *getenv();
X    char           *tgetstr();
X    char           *name;
X
X    tospaces(window0, MAX_Y * MAX_X);
X    tospaces(window1, MAX_Y * MAX_X);
X    _csrx = 9000;
X    _csry = 9000;
X    _rx = 9000;
X    _ry = 9000;
X
X    /*
X     * turn off echo and crmod; turn on cbreak mode 
X     */
X    gtty(0, &tty);
X    orig_tty = tty;		/* structure assignment */
X    ospeed = tty.sg_ospeed;
X    tty.sg_flags &= ~ECHO;
X    tty.sg_flags &= ~CRMOD;
X    tty.sg_flags |= CBREAK;
X    stty(0, &tty);
X
X    ioctl(0, TIOCGLTC, &ltc);
X    orig_ltc = ltc;		/* structure assignment */
X    ltc.t_flushc = -1;		/* ignore whatever ctrl-o does */
X    ltc.t_suspc = -1;		/* ctrl-z */ 
X    ltc.t_dsuspc = -1;		/* ctrl-y */
X    ioctl(0, TIOCSLTC, &ltc);
X
X
X    /*
X     * ignore control-s and ctrl-c 
X     */
X    ioctl(0, TIOCGETC, &tc);
X    orig_tc = tc;		/* structure assignment */
X    tc.t_stopc = -1;
X    tc.t_intrc = -1;
X    ioctl(0, TIOCSETC, &tc);
X
X    switch (tgetent(bp, name = getenv("TERM")))
X    {
X   	case -1:
X		resetty();
X		printf("can't open termcap file.\n");
X		return 0;
X		break;
X    case 0:
X		resetty();
X		printf("No termcap entry for %s.\n", name);
X		return 0;
X		break;
X    }
X
X    tc_ce = tgetstr("ce", &area);	/* not used yet */
X    tc_cm = tgetstr("cm", &area);
X    tc_cl = tgetstr("cl", &area);
X    tc_up = tgetstr("up", &area);
X    tc_do = tgetstr("do", &area);
X
X    if (!(tc_cm && tc_cl && tc_up && tc_do))
X    {
X	resetty();
X	puts("Your terminal must have cursor movement capabilities.");
X	return 0;
X    }
X    return 1;
X}
X
Xputch(ch)
X    char            ch;
X{
X	putchar(ch);
X}
X
Xresetty()
X{
X    stty(0, &orig_tty);
X    ioctl(0, TIOCSETC, &orig_tc);
X    ioctl(0, TIOCSLTC, &orig_ltc);
X}
X
Xcsr_draw(y1, x1, y2, x2)
X    int             y1, x1;
X    reg             y2, x2;
X{
X    reg             i, j;
X
X    for (i = y1; i <= y2; ++i)
X    {
X		for (j = x1; j <= x2; ++j)
X		{
X		    if (window0[i][j] != window1[i][j])
X		    {
X				if (i == _ry)
X				{
X				    if (_rx == j);
X				    else
X				    if (j == 0)
X				    {
X						putchar('\r');
X				    } else
X				    if (j < _rx && j > _rx - 3)
X				    {
X						while (_rx-- > j)
X						    putchar('\b');
X				    } else
X				    if (j > _rx && j < _rx + 3)
X				    {
X						while (_rx < j)
X						    putchar(window0[i][_rx++]);
X				    } else
X						csr(i, j);
X				} else
X				if (i == _ry - 1)
X				{
X				    if (j == _rx)
X						tputs(tc_up, 0, putch);
X				    else
X				    if (j < _rx && j > _rx - 3)
X				    {
X						tputs(tc_up, 0, putch);
X						while (_rx-- > j)
X						    putchar('\b');
X				    } else
X				    if (j > _rx && j < _rx + 3)
X				    {
X						tputs(tc_up, 0, putch);
X						while (_rx < j)
X						    putchar(window0[i][_rx++]);
X				    } else
X						csr(i, j);
X				} else
X				if (i == _ry + 1)
X				{
X				    if (j == _rx)
X						tputs(tc_do, 0, putch);
X				    else
X				    if (j < _rx && j > _rx - 3)
X				    {
X						tputs(tc_do, 0, putch);
X						while (_rx-- > j)
X						    putchar('\b');
X				    } else
X				    if (j > _rx && j < _rx + 3)
X				    {
X						tputs(tc_do, 0, putch);
X						while (_rx < j)
X						    putchar(window0[i][_rx++]);
X				    } else
X						csr(i, j);
X				} else
X				    csr(i, j);
X				putchar(window1[i][j]);
X				window0[i][j] = window1[i][j];
X				_ry = i;
X				if (j + 1 == MAX_X)
X				{
X				    if (nowrapping)
X						_rx = 100;
X				    else
X				    {
X						_rx = 0;
X						++_ry;
X				    }
X				} else
X				    _rx = j + 1;
X			}
X		}
X    }
X   	fflush(stdout);
X}
X
X/* VARARGS 0 */
Xprintc(fmt, args)
X    char           *fmt, **args;
X{
X    FILE            jnk;
X
X    jnk._flag = _IOWRT + _IOSTRG;
X    jnk._ptr = &window1[_csry][_csrx];
X    jnk._cnt = 32014;
X    _doprnt(fmt, &args, &jnk);
X    _csrx += jnk._ptr - &window1[_csry][_csrx];
X}
X
Xmvaddstr(y, x, s)
X    int             y, x;
X    reg char       *s;
X{
X    reg char       *w = &window1[y][x];
X
X    while (*s)
X	*w++ = *s++;
X    _csry = y;
X    _csrx = x + w - &window1[y][x];
X}
X
Xclear(y1, x1, y2, x2)
X{
X    reg int         l;
X    reg int         d = x2 - x1 + 1;
X    for (l = y1; l <= y2; ++l)
X	tospaces(&window1[l][x1], d);
X}
X
Xclear0(y1, x1, y2, x2)
X{
X    reg int         l;
X    reg int         d = x2 - x1 + 1;
X    for (l = y1; l <= y2; ++l)
X	tospaces(&window0[l][x1], d);
X}
X
Xtospaces(p, n)
X    char           *p;
X    int             n;
X{
X    while (n--)
X	*p++ = ' ';
X}
X
X
X/*
X * This would be faster, but this isn't allowed. .text .globl	_tospaces 
X *
X * _tospaces: .word	0x0 movc5	$0,0,$32,8(ap),*4(ap) ret 
X */
X
X/* Refresh the whole screen */
Xint             refreshing;
Xrefresh()
X{
X    refreshing = 1;
X    nowrapping = 1;
X    csr_draw(0, 0, MAX_Y - 1, MAX_X - 1);
X    fflush(stdout);
X    refreshing = 0;
X}
X
X/* added by jon luini, niteowl@ssyx */
Xsave_screen(y1, x1, y2, x2)
Xint	y1,	/* the x, y co-ordinates of the area to be saved */
X	x1,
X	y2,
X	x2;
X{
X	reg int	i, 
X		j;
X
X	for (i = y1; i <= y2; i++)
X		for (j = x1; j <= x2; j++)
X			window2[i][j] = window1[i][j];
X}
X
Xrestore_screen(y1, x1, y2, x2)
Xint	y1,	/* the x, y co-ordinates of the area to be restored */
X	x1,
X	y2,
X	x2;
X{
X	reg int	i, 
X		j;
X
X	for (i = y1; i <= y2; i++)
X		for (j = x1; j <= x2; j++)
X			window1[i][j] = window2[i][j];
X}
END_OF_FILE
if test 6750 -ne `wc -c <'csr.c'`; then
    echo shar: \"'csr.c'\" unpacked with wrong size!
fi
# end of 'csr.c'
fi
if test -f 'define_shapes.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'define_shapes.c'\"
else
echo shar: Extracting \"'define_shapes.c'\" \(9074 characters\)
sed "s/^X//" >'define_shapes.c' <<'END_OF_FILE'
X/*
X** written by adam margulies [email-masked]
X**                           {...}!ucbvax!ucscc!ssyx!vespa
X**
X** permission is granted to freely distribute this code provided that you:
X**
X** 1) don't charge for it
X** 2) leave my name and header on it
X** 3) clearly document your changes and place your name on them
X**
X*/
X/* Tetris: define_shapes()                                              */
X/*                                                                      */
X/*  This function defines the shape tables to be used in Tetris.        */
X/*  There are eight possible shapes, each made of four contiguous       */
X/*  blocks. This is the fastest way I know how to make the shape        */
X/*  tables available and it seems to work quite well. The program       */
X/*  accesses the tables using bitwise operators.                        */
X/*                                                                      */
X/*  The structure shape contains four table arrays which are the        */
X/*  bitwise representations of the four horizontal lines of each        */
X/*  block, each block being represented on a 4 X 4 grid. Sixteen        */
X/*  such table entries are needed to represent all four rotations       */
X/*  of the block.                                                       */
X/*                                                                      */
X/*  Pointv is the point value for each rotation of the block.           */
X/*  It is used for scoring.                                             */
X/*                                                                      */
X/*  For drawing and collision detection purposes it is necessary        */
X/*  to know the "height" and "width" of the block for each rotation     */
X/*  The offset records how far from the upper left hand corner of       */
X/*  the 4 X 4 array the block actually starts. It is very fast.         */
X/*  The offset is a flag byte, with the following format:               */
X
X/*    bit 7         bit 6         bit 5         bit 4
X   rot0 yoffset, rot0 xoffset, rot1 yoffset, rot1 xoffset,
X
X   rot2 yoffset, rot2 xoffset, rot3 yoffset, rot3 xoffset.
X      bit 3         bit 2         bit 1         bit 0      */
X/*                                                                      */
X/* The color variable stores the character that the shape will be       */
X/* "painted" onto the screen with, it is different for each block.      */
X/*                                                                      */
X
X#include "tetris.h"
X
Xvoid define_shapes()
X{
X
X    /* begin shape 0 definition, four rotations */
X
X    shape[0].table[0][0] = 0;  
X    shape[0].table[1][0] = 15;  /* #### */
X    shape[0].table[2][0] = 0; 
X    shape[0].table[3][0] = 0; 
X    shape[0].pointv[0] = 5; 
X
X    shape[0].table[0][1] = 4;   /*  #   */
X    shape[0].table[1][1] = 4;   /*  #   */
X    shape[0].table[2][1] = 4;   /*  #   */
X    shape[0].table[3][1] = 4;   /*  #   */
X    shape[0].pointv[1] = 8; 
X
X    shape[0].table[0][2] = 0; 
X    shape[0].table[1][2] = 15; /* #### */
X    shape[0].table[2][2] = 0; 
X    shape[0].table[3][2] = 0; 
X    shape[0].pointv[2] = 5; 
X
X    shape[0].table[0][3] = 4;   /*  #    */
X    shape[0].table[1][3] = 4;   /*  #    */
X    shape[0].table[2][3] = 4;   /*  #    */
X    shape[0].table[3][3] = 4;   /*  #    */
X    shape[0].pointv[2] = 8; 
X
X    shape[0].width = 4; 
X    shape[0].height = 1; 
X    shape[0].offset = 153;
X    shape[0].color = '#';
X
X    /* begin shape 1 definition, four rotations */
X
X    shape[1].table[0][0] = 12;  /* ##   */
X    shape[1].table[1][0] = 12;  /* ##   */
X    shape[1].table[2][0] = 0;   /*      */
X    shape[1].table[3][0] = 0;   /*      */
X    shape[1].pointv[0] = 6; 
X
X    shape[1].table[0][1] = 12;  /* ##   */
X    shape[1].table[1][1] = 12;  /* ##   */
X    shape[1].table[2][1] = 0;   /*      */
X    shape[1].table[3][1] = 0;   /*      */
X    shape[1].pointv[1] = 6; 
X
X    shape[1].table[0][2] = 12;  /* ##   */
X    shape[1].table[1][2] = 12;  /* ##   */
X    shape[1].table[2][2] = 0;   /*      */
X    shape[1].table[3][2] = 0;   /*      */
X    shape[1].pointv[2] = 6; 
X
X    shape[1].table[0][3] = 12;  /* ##   */
X    shape[1].table[1][3] = 12;  /* ##   */
X    shape[1].table[2][3] = 0;   /*      */
X    shape[1].table[3][3] = 0;   /*      */
X    shape[1].pointv[3] = 6; 
X
X    shape[1].width = 2; 
X    shape[1].height = 2; 
X    shape[1].offset = 0;
X    shape[1].color = '$';
X
X    /* begin shape 2 definition, four rotations */
X
X    shape[2].table[0][0] = 4;  /*  #  */
X    shape[2].table[1][0] = 14; /* ### */
X    shape[2].table[2][0] = 0;  /*     */
X    shape[2].table[3][0] = 0;  /*     */
X    shape[2].pointv[0] = 5; 
X
X    shape[2].table[0][1] = 4;  /*  #  */
X    shape[2].table[1][1] = 6;  /*  ## */
X    shape[2].table[2][1] = 4;  /*  #  */
X    shape[2].table[3][1] = 0;  /*     */
X    shape[2].pointv[0] = 5; 
X
X    shape[2].table[0][2] = 0;  /*     */
X    shape[2].table[1][2] = 14; /* ### */
X    shape[2].table[2][2] = 4;  /*  #  */
X    shape[2].table[3][2] = 0;  /*     */
X    shape[2].pointv[2] = 6; 
X
X    shape[2].table[0][3] = 4;  /*  #  */
X    shape[2].table[1][3] = 12; /* ##  */
X    shape[2].table[2][3] = 4;  /*  #  */
X    shape[2].table[3][3] = 0;  /*     */
X    shape[2].pointv[3] = 5; 
X
X    shape[2].width = 3; 
X    shape[2].height = 2; 
X    shape[2].offset = 24;
X    shape[2].color = '%';
X
X    /* begin shape 3 definition, four rotations */
X
X    shape[3].table[0][0] = 12; /* ##  */
X    shape[3].table[1][0] = 6;  /*  ## */
X    shape[3].table[2][0] = 0;  /*     */
X    shape[3].table[3][0] = 0;  /*     */
X    shape[3].pointv[0] = 6; 
X
X    shape[3].table[0][1] = 4;  /*  #  */
X    shape[3].table[1][1] = 12; /* ##  */
X    shape[3].table[2][1] = 8;  /* #   */
X    shape[3].table[3][1] = 0;  /*     */
X    shape[3].pointv[1] = 7; 
X
X    shape[3].table[0][2] = 12; /* ##  */
X    shape[3].table[1][2] = 6;  /*  ## */
X    shape[3].table[2][2] = 0;  /*     */
X    shape[3].table[3][2] = 0;  /*     */
X    shape[3].pointv[2] = 6; 
X
X    shape[3].table[0][3] = 4;  /*  #  */
X    shape[3].table[1][3] = 12; /* ##  */
X    shape[3].table[2][3] = 8;  /* #   */
X    shape[3].table[3][3] = 0;  /*     */
X    shape[3].pointv[3] = 7; 
X
X    shape[3].width = 3; 
X    shape[3].height = 2; 
X    shape[3].offset = 0;
X    shape[3].color = '@';
X
X    /* begin shape 4 definition, four rotations */
X
X    shape[4].table[0][0] = 6;  /*  ## */
X    shape[4].table[1][0] = 12; /* ##  */
X    shape[4].table[2][0] = 0;  /*     */
X    shape[4].table[3][0] = 0;  /*     */
X    shape[4].pointv[0] = 6; 
X
X    shape[4].table[0][1] = 8;  /* #   */
X    shape[4].table[1][1] = 12; /* ##  */
X    shape[4].table[2][1] = 4;  /*  #  */
X    shape[4].table[3][1] = 0;  /*     */
X    shape[4].pointv[1] = 7; 
X
X    shape[4].table[0][2] = 6;  /*  ## */
X    shape[4].table[1][2] = 12; /* ##  */
X    shape[4].table[2][2] = 0;  /*     */
X    shape[4].table[3][2] = 0;  /*     */
X    shape[4].pointv[2] = 6; 
X
X    shape[4].table[0][3] = 8;  /* #   */
X    shape[4].table[1][3] = 12; /* ##  */
X    shape[4].table[2][3] = 4;  /*  #  */
X    shape[4].table[3][3] = 0;  /*     */
X    shape[4].pointv[3] = 7; 
X
X    shape[4].width = 3; 
X    shape[4].height = 2; 
X    shape[4].offset = 0;
X    shape[4].color = '&';
X
X    /* begin shape 5 definition, four rotations */
X
X    shape[5].table[0][0] = 2;  /*   # */
X    shape[5].table[1][0] = 14; /* ### */
X    shape[5].table[2][0] = 0;  /*     */
X    shape[5].table[3][0] = 0;  /*     */
X    shape[5].pointv[0] = 6; 
X
X    shape[5].table[0][1] = 8;  /* #   */
X    shape[5].table[1][1] = 8;  /* #   */
X    shape[5].table[2][1] = 12; /* ##  */
X    shape[5].table[3][1] = 0;  /*     */
X    shape[5].pointv[1] = 7; 
X
X    shape[5].table[0][2] = 14; /* ### */
X    shape[5].table[1][2] = 8;  /* #   */
X    shape[5].table[2][2] = 0;  /*     */
X    shape[5].table[3][2] = 0;  /*     */
X    shape[5].pointv[2] = 6; 
X
X    shape[5].table[0][3] = 12; /* ##  */
X    shape[5].table[1][3] = 4;  /*  #  */
X    shape[5].table[2][3] = 4;  /*  #  */
X    shape[5].table[3][3] = 0;  /*     */
X    shape[5].pointv[3] = 7; 
X
X    shape[5].width = 3; 
X    shape[5].height = 2; 
X    shape[5].offset = 0;
X    shape[5].color = '*';
X
X    /* begin shape 6 definition, four rotations */
X
X    shape[6].table[0][0] = 14; /* ### */
X    shape[6].table[1][0] = 2;  /*   # */
X    shape[6].table[2][0] = 0;  /*     */
X    shape[6].table[3][0] = 0;  /*     */
X    shape[6].pointv[0] = 6; 
X
X    shape[6].table[0][1] = 4;  /*  #  */
X    shape[6].table[1][1] = 4;  /*  #  */
X    shape[6].table[2][1] = 12; /* ##  */
X    shape[6].table[3][1] = 0;  /*     */
X    shape[6].pointv[1] = 7; 
X
X    shape[6].table[0][2] = 8;  /* #   */
X    shape[6].table[1][2] = 14; /* ### */
X    shape[6].table[2][2] = 0;  /*     */
X    shape[6].table[3][2] = 0;  /*     */
X    shape[6].pointv[2] = 6; 
X
X    shape[6].table[0][3] = 12; /* ##  */
X    shape[6].table[1][3] = 8;  /* #   */
X    shape[6].table[2][3] = 8;  /* #   */
X    shape[6].table[3][3] = 0;  /*     */
X    shape[6].pointv[3] = 7; 
X
X    shape[6].width = 3; 
X    shape[6].height = 2; 
X    shape[6].offset = 0;
X    shape[6].color = '+';
X}
END_OF_FILE
if test 9074 -ne `wc -c <'define_shapes.c'`; then
    echo shar: \"'define_shapes.c'\" unpacked with wrong size!
fi
# end of 'define_shapes.c'
fi
if test -f 'end_game.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'end_game.c'\"
else
echo shar: Extracting \"'end_game.c'\" \(6294 characters\)
sed "s/^X//" >'end_game.c' <<'END_OF_FILE'
X/*
X** written by adam margulies [email-masked]
X**                           {...}!ucbvax!ucscc!ssyx!vespa
X**
X** permission is granted to freely distribute this code provided that you:
X**
X** 1) don't charge for it
X** 2) leave my name and header on it
X** 3) clearly document your changes and place your name on them
X**
X*/
X/* Tetris: end_game()                                                      */
X/*                                                                         */
X/*  When the player quits or loses this function is called.                */
X/*  It updates the high-score file and then exits after resetting the      */
X/*  tty.                                                                   */
X#include "tetris.h"
X#include "sys/file.h"
X
Xvoid end_game()
X{
X	struct sgttyb *thistty;
X    int i,counter, flag=0; /* i and counter are counters, flag is used
X							  to show that the current user's score has been
X							  written and should not be written again */
X	int ncp;
X    FILE *fp, *fopen();
X    long clock;
X    int tmp;
X    char *ctime();
X	char c;
X	char monster[10], pts[20];
X	char levelstr[15], aan[5];
X	struct tm *tmstr;
X	int year;
X	tmstr = (struct tm *)malloc(sizeof(struct tm));
X	thistty = (struct sgttyb *)malloc(sizeof(struct sgttyb));
X
X    SIGHOLD(14);
X
X    time(&clock);
X	tmstr = localtime(&clock);
X	year = tmstr->tm_year;
X
X	unlink(rcd_file);
X
X	if (!strcmp(username, "\0")) {
X		if (!getenv("NAME"))
X			sprintf(username, "doofus");
X		else
X			sprintf(username,"%s", getenv("NAME"));
X	}
X
X	if ((fp = fopen(HIGHSCOREFILE, "r+")) == NULL){
X		SIGHOLD(14);
X		cls();
X		csr(23,0);
X		resetty();
X		fprintf(stderr, "%s\n", HIGHSCOREFILE);
X		perror("opening highscore file");
X		exit(3);
X	}
X
X	flock(fileno(fp), LOCK_EX);
X    for(counter=0;counter<15;counter++){
X        fscanf(fp, "%d\n", &high_score[counter]);
X        fscanf(fp, "%s\n", high_user[counter]);
X        fgets(high_name[counter], 255, fp);
X		for (i=0; i<255; i++)
X			if (high_name[counter][i] == '\n')
X				high_name[counter][i] = '\0';	
X    }
X
X	rewind(fp);
X
X    for(counter=0;counter<15;counter++){
X		if (points > high_score[counter]) {
X			fprintf(fp, "%d\n%s\n%s\n", points, user_info->pw_name,
X									  username);
X
X			for (i=counter; i<15; i++)
X				if (strcmp(high_user[i], user_info->pw_name) != 0)
X					fprintf(fp, "%d\n%s\n%s\n", high_score[i], high_user[i],
X											  high_name[i]);
X			counter=15;
X		}
X		else  fprintf(fp, "%d\n%s\n%s\n", high_score[counter],
X								high_user[counter], high_name[counter]);
X		if (strcmp(high_user[counter] ,user_info->pw_name) == 0) {
X			for (i=counter+1; i<15; i++)
X				fprintf(fp, "%d\n%s\n%s\n", high_score[i], high_user[i],
X										  high_name[i]);
X			counter=15;
X		} 
X    }
X	flock(fileno(fp), LOCK_UN);
X    fclose(fp);
X
X	if ((fp = fopen(HIGHSCOREFILE, "r")) == NULL){
X		SIGHOLD(14);
X		cls();
X		csr(23,0);
X		resetty();
X		fprintf(stderr, "%s\n", HIGHSCOREFILE);
X		perror("opening highscore file");
X		exit(3);
X	}
X
X    for(counter=0;counter<10;counter++){
X        fscanf(fp, "%d\n", &high_score[counter]);
X        fscanf(fp, "%s\n", high_user[counter]);
X        fgets(high_name[counter], 255, fp);
X		for (i=0; i<255; i++)
X			if (high_name[counter][i] == '\n')
X				high_name[counter][i] = '\0';	
X        move(10+counter,0);
X        printc("%2.2d. %7.7d (%s)    ", counter+1, high_score[counter],
X                high_user[counter]);
X    }
X    fclose(fp);
X    csr_draw(10,0,20,30);
X
X    for (i=2; i<12; i++) {
X        mvaddstr(i,35,"**********");
X        mvaddstr(23-i,35,"**********");
X        csr_draw(2,35,21,44);
X    }
X    mvaddstr(11,35,"GAME  OVER");
X    csr_draw(11,35,11,44);
X
X    if (getuid() != MASTERUID) {
X		if ((fp = fopen(MONITORFILE, "a")) == NULL){
X			SIGHOLD(14);
X			cls();
X			csr(23,0);
X			resetty();
X			fprintf(stderr, "%s\n", MONITORFILE);
X			perror("opening monitor file");
X			exit(3);
X		}
X
X		flock(fileno(fp), LOCK_EX);
X        fprintf(fp, "%s %d %s", user_info->pw_name, points, ctime(&clock));
X		flock(fileno(fp), LOCK_UN);
X        fclose(fp);
X    }
X
X	if(disp_tomb) {
X		csr(0,0);
X
X		cls();
X			sprintf(pts, "%d Pts", points);
X			sprintf(levelstr, "on level %d", level);
X			switch(current->shape) {
X				case 0:
X					sprintf(monster,"bar");
X					sprintf(aan, "a");
X					break;
X				case 1:
X					sprintf(monster,"block");
X					sprintf(aan, "a");
X					break;
X				case 2:
X					sprintf(monster,"tee");
X					sprintf(aan, "a");
X					break;
X				case 3:
X					sprintf(monster,"zee");
X					sprintf(aan, "a");
X					break;
X				case 4:
X					sprintf(monster,"ess");
X					sprintf(aan, "an");
X					break;
X				case 5:
X					sprintf(monster,"elle");
X					sprintf(aan, "an");
X					break;
X				case 6:
X					sprintf(monster,"belle");
X					sprintf(aan, "a");
X					break;
X				case 7:
X					sprintf(monster,"Q key");
X					sprintf(aan, "a");
X			}
X				   mvaddstr(8,15,"__________");
X				 mvaddstr(09,14,"/          \\");
X				mvaddstr(10,13,"/    REST    \\");
X			   mvaddstr(11,12,"/      IN      \\");
X			  mvaddstr(12,11,"/     PEACE      \\");
X			 mvaddstr(13,10,"/                  \\");
X			 mvaddstr(14,10,"|                  |");
X			 mvaddstr(15,10,"|                  |");
X			 mvaddstr(16,10,"|                  |");
X			 mvaddstr(17,10,"|                  |");
X			 mvaddstr(18,10,"|                  |");
X			 mvaddstr(19,10,"|                  |");
X			 mvaddstr(20,9,"*|     *  *  *      | *");
X	 mvaddstr(21,1,"________)/\\\\_//(\\/(/\\)/\\//\\/|_)________");
X		mvaddstr(14,19 - (strlen(user_info->pw_name)/2),user_info->pw_name);
X		mvaddstr(15,19 - (strlen(pts)/2), pts);
X		move(16,15 - strlen(aan) + 1);
X		printc("Killed by %s", aan);
X		mvaddstr(17,19 - (strlen(monster)/2), monster);
X		mvaddstr(18,19 - (strlen(levelstr)/2), levelstr);
X		move(19,18);
X		printc("19%d", year);
X		csr_draw(0,0,23,79);
X
X			csr(22,0);
X		printc("[Viciously strike a poor, helpless key]");
X		csr_draw(22,0,22,79);
X		getchar();
X		clear(22,0,22,79);
X		csr_draw(22,0,22,79);
X	}
X
X
X	if(!disp_high)
X		display_high();
X	csr(23,0);
X	resetty();
X
X	/* make writable again */
X	if(nowrite & 2) {
X		ttystat->st_mode |= 16;
X		chmod(ttyname(0), ttystat->st_mode);
X	}
X
X	if(addict) {
X		do
X			ioctl(1, TIOCOUTQ, &ncp);
X		while(ncp != 0);
X		signal(SIGHUP, SIG_IGN);
X		signal(SIGALRM, SIG_IGN);
X		thistty->sg_ispeed = 0;
X		thistty->sg_ospeed = 0;
X		ioctl(0, TIOCSETP, thistty);
X		exit(0);
X	}
X	else
X		exit(0);
X}
END_OF_FILE
if test 6294 -ne `wc -c <'end_game.c'`; then
    echo shar: \"'end_game.c'\" unpacked with wrong size!
fi
# end of 'end_game.c'
fi
if test -f 'init_tetris.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'init_tetris.c'\"
else
echo shar: Extracting \"'init_tetris.c'\" \(6572 characters\)
sed "s/^X//" >'init_tetris.c' <<'END_OF_FILE'
X/*
X** written by adam margulies [email-masked]
X**                           {...}!ucbvax!ucscc!ssyx!vespa
X**
X** permission is granted to freely distribute this code provided that you:
X**
X** 1) don't charge for it
X** 2) leave my name and header on it
X** 3) clearly document your changes and place your name on them
X**
X*/
X/* Tetris: init_tetris.c                                                  */
X/*                                                                        */
X/* this is one of the first functions called. It gets user info,          */
X/* seeds the random number generator, draws the screen, and sets the      */
X/* interrupt timer.                                                       */
X#include "tetris.h"
X
Xvoid init_tetris()
X{
X    FILE *fp;
X    struct passwd *getpwuid();
X    int i,j,c,counter;
X    long ctime;
X    void get_level(), define_shapes(), cursive(), drop_block(), intr_hand();
X    void cont_hand(), save_game();
X    char *getenv(), line[15], file[80];
X    struct stat buf;
X
X	int fd;
X	struct utmp entry;
X	struct passwd *pwd;
X
X	points = 0;
X	lines = 0;
X
X    define_shapes();
X    cls();
X
X	signal(SIGCONT, cont_hand); /* cont trap */
X	signal(SIGHUP, save_game); /* sighup trap */
X
X    user_info = getpwuid(getuid());
X    current = (struct shape *)malloc(sizeof(struct shape));
X    next = (struct shape *)malloc(sizeof(struct shape));
X	key = (struct keystr *)malloc(sizeof(struct keystr));
X	ttystat = (struct stat *)malloc(sizeof(struct stat));
X
X	/*construct the save file name*/
X
X	if(getenv("HOME") != NULL) {
X		strcpy(rcd_file, getenv("HOME"));
X		strcat(rcd_file, "/tetris.save");
X	} else {
X		strcpy(rcd_file, user_info->pw_dir);
X		strcat(rcd_file, "/tetris.save");
X	}
X
X    srandom(getpid());
X
X	/* read in file perms on user's tty and then determine if writable */
X	stat(ttyname(0), ttystat);
X
X	ttystat->st_mode &= 511;
X	if(ttystat->st_mode & 16)
X		nowrite |= 2;
X
X	if(keystr[0] == '\0')
X		strcpy(keystr, "hljk nb");
X
X	key->left = keystr[0];
X	key->right = keystr[1];
X	key->rotleft = keystr[2];
X	key->rotright = keystr[3];
X	key->drop = keystr[4];
X	key->togdisp = keystr[5];
X	key->togshad = keystr[6];
X
X    mvaddstr(01,34,"+----------+");
X    mvaddstr(22,34,"+----------+");
X	for (i=0; i < 20; i++) 
X		mvaddstr(i+2,34,"|          |");
X
X	/* restore the game if necessary */
X	if (access(rcd_file, R_OK) == 0 ) {
X		stat(rcd_file, &buf);
X		if ((fp = fopen(rcd_file, "r")) == NULL){
X			SIGHOLD(14);
X			cls();
X			csr(23,0);
X			resetty();
X			fprintf(stderr, "%s\n", rcd_file);
X			perror("opening save file");
X			exit(3);
X		}
X
X		for (i=0; i < 20; i++)
X			for (j=0; j < 10; j++) {
X				while((c = fgetc(fp)) == '\n');
X				window1[i+2][j+35] = c;	
X			}
X		fscanf(fp, "%ld\n", &ctime);
X		if (ctime + 3 < buf.st_ctime) {
X			csr(23,0);
X			resetty();
X			printf("Panic!\n");
X			unlink(rcd_file);
X			exit(1);
X		}
X		fscanf(fp, "%d\n", &version);
X		if(version != VERSION) {
X			csr(23,0);
X			resetty();
X			printf("Sorry your save file is out of date.\n");
X			unlink(rcd_file);
X			exit(1);
X		}
X		fscanf(fp, "%d\n%d\n%d\n", &points, &level, &lines);
X		fscanf(fp, "%d\n", &disp_next);
X		fscanf(fp, "%d\n", &shadow);
X		fscanf(fp, "%d\n", &disp_tomb);
X		fscanf(fp, "%d\n", &disp_high);
X		fscanf(fp, "%d\n%d\n", &cury, &curx);
X		fscanf(fp, "%d\n%d\n", &current->shape, &current->rot);
X		fscanf(fp, "%d\n", &current->was_shown);
X		fscanf(fp, "%d\n", &current->was_shadowed);
X		fscanf(fp, "%d\n%d\n", &next->shape, &next->rot);
X		fscanf(fp, "%d\n", &next->was_shown);
X		fscanf(fp, "%d\n", &next->was_shadowed);
X		fscanf(fp, "%d\n", &addict);
X		key->right = fgetc(fp);
X		fgetc(fp);
X		key->left = fgetc(fp);
X		fgetc(fp);
X		key->rotright = fgetc(fp);
X		fgetc(fp);
X		key->rotleft = fgetc(fp);
X		fgetc(fp);
X		key->drop = fgetc(fp);
X		fgetc(fp);
X		key->togdisp = fgetc(fp);
X		fgetc(fp);
X		key->togshad = fgetc(fp);
X		fgetc(fp);
X
X		if (current->rot == 0 || current->rot == 2) {
X			current->width = shape[current->shape].width;
X			current->height = shape[current->shape].height;
X		}
X		if (current->rot == 1 || current->rot == 3) {
X			current->width = shape[current->shape].height;
X			current->height = shape[current->shape].width;
X		}
X		current->color  = shape[current->shape].color;
X		current->offset = shape[current->shape].offset;
X		current->pointv = shape[current->shape].pointv[current->rot];
X		next->color  = shape[next->shape].color;
X		next->offset = shape[next->shape].offset;
X		next->pointv = shape[next->shape].pointv[next->rot];
X	}
X
X    csr_draw(1,34,22,46);
X
X    cursive();
X	move(3,20);
X	printc("%2.2f", (VERSION/10.0));
X	csr_draw(3,20,3,22);
X
X	if (access(rcd_file, R_OK) != 0 ) {
X		next->shape = random() % 7;
X		next->rot = random() % 4;
X		next->color = '0';
X		next->pointv = shape[next->shape].pointv[next->rot];
X	}
X
X    if (next->rot == 0 || next->rot == 2) {
X        next->width = shape[next->shape].width;
X        next->height = shape[next->shape].height;
X    }
X    if (next->rot == 1 || next->rot == 3) {
X        next->width = shape[next->shape].height;
X        next->height = shape[next->shape].width;
X    }
X
X    next->offset = shape[next->shape].offset; 
X
X	if (access(rcd_file, R_OK) != 0 ) {
X		if(disp_open && level == 0 && rubble == 0)
X			get_level();
X		make_rubble();
X		csr_draw(5,19,21,62);
X		setup_next();
X	}
X	else if (disp_next)
X		print_shape(next->shape, 17, 6, next->rot, next->color);
X
X	if (access(rcd_file, R_OK) == 0 && shadow == 1 ) 
X		draw_shadow();
X
X    move(6,5);
X    printc("next block:");
X    csr_draw(6,5,6,16);
X
X    move(0,65);
X    printc("score: %7.7d", points);
X    move(1,65);
X    printc("lines: %3.3d", lines);
X    move(2,65);
X    printc("level: %2.2d", level);
X    csr_draw(0,65,2,79);
X    move(22,60);
X    printc("last mod: %s", LASTDATE);
X    csr_draw(22,60,22,78);
X
X	if ((fp = fopen(HIGHSCOREFILE, "r")) == NULL){
X		SIGHOLD(14);
X		cls();
X		csr(23,0);
X		resetty();
X		fprintf(stderr, "%s\n", HIGHSCOREFILE);
X		perror("opening highscore file");
X		exit(3);
X	}
X
X    for(counter=0;counter<10;counter++){
X        fscanf(fp, "%d\n", &high_score[counter]);
X        fscanf(fp, "%255s\n", high_user[counter]);
X        fgets(high_name[counter], 255, fp);
X        move(10+counter,0);
X        printc("%2.2d. %7.7d (%s)    ", counter+1, high_score[counter],
X                high_user[counter]);
X    }
X    fclose(fp);
X    csr_draw(10,0,20,30);
X
X    move(22,0);
X    printc("? for help");
X    csr_draw(22,0,22,10);
X
X    bzero(&timer, sizeof(timer));
X    bzero(&otimer, sizeof(otimer));
X    timer.it_interval.tv_usec = 500000;
X    timer.it_value.tv_usec = 500000;
X    setitimer(ITIMER_REAL, &timer, 0);
X    signal(SIGALRM, drop_block);
X	set_level();
X}
END_OF_FILE
if test 6572 -ne `wc -c <'init_tetris.c'`; then
    echo shar: \"'init_tetris.c'\" unpacked with wrong size!
fi
# end of 'init_tetris.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(7377 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/*
X** written by adam margulies [email-masked]
X**                           {...}!ucbvax!ucscc!ssyx!vespa
X**
X** permission is granted to freely distribute this code provided that you:
X**
X** 1) don't charge for it
X** 2) leave my name and header on it
X** 3) clearly document your changes and place your name on them
X**
X*/
X/* Tetris: a game supposedly written by some Soviet kid.                     */
X/*                                                                           */
X/* Last kludge: February 23, 1989                                            */
X/* Guilty party: adam margulies, [email-masked]                         */
X/*                                                                           */
X/* This program contains some hopelessly inbred array operations.            */
X/* It also is a monster to behold.                                           */
X/*                                                                           */
X/* All hope abandon, ye who enter here.                                      */
X/*                                                                           */
X/* Tetris: main.c                                                            */
X/*                                                                           */
X/*    main loop, waits for keypress and then passes it to process_input()    */
X/*                                                                           */
X
X#include "tetris.h"
X
Xint	opterr = 1;
Xint	optind = 1;
Xint	optopt;
Xchar	*optarg;
X
Xmain(argc, argv, envp)
Xint argc;
Xchar **argv, **envp;
X{
X	/* I do a lot of voids, so that lint doesn't complain */
X	void init_tetris(), print_shape(), setup_next(), drop_block(); 
X
X	char c, input;						/* holds user's keypresses */
X	char tetrisenv[1024];
X	char buf[1024];
X	int i=0, j=0, k=0, disp_score;
X
X	opterr = 0;
X	disp_next = 1;
X	disp_open = 1;
X	shadow = 1;
X
X	if(argv[1] && !strcmp(argv[1], "-")){
X		fprintf(stderr, "Usage: %s [-] [-whotnbsa] [-L level] [-N name] [-O oblev] [-K keys]\n", argv[0]);
X		fprintf(stderr, "\t- - give this summary of usage\n");
X		fprintf(stderr, "\tw - makes you unwritable for duration of game\n");
X		fprintf(stderr, "\th - suppress printing of high score list\n");
X		fprintf(stderr, "\to - suppress opening screen selection box\n");
X		fprintf(stderr, "\tt - display roguelike tombstone\n");
X		fprintf(stderr, "\tn - turn off next block display\n");
X		fprintf(stderr, "\tb - turn off shadowing\n");
X		fprintf(stderr, "\ts - display high score list and exit\n");
X		fprintf(stderr, "\ta - addict option, logs you out when game is over\n");
X		fprintf(stderr, "\tN [name] - use [name] for high score list\n");
X		fprintf(stderr, "\tL [level] - start at [level] of difficulty\n");
X		fprintf(stderr, "\tO [oblev] - generate [oblev]s of debris\n");
X		fprintf(stderr, "\tK [keys] - map control keys to [keys]\n");
X		fprintf(stderr, "\t\tmail suggestions to [email-masked]\n");
X		fprintf(stderr, "\t\t                    {...}!ucbvax!ucscc!ssyx!vespa\n");
X		exit(0);
X	}
X
X	/* if the user has set an environment variable "TETRIS" then process it */
X
X	if(argc<2 && getenv("TETRIS") == NULL) {
X		i=0, j=0, k=0;
X		
X		strcpy(tetrisenv, getenv("TETRIS"));
X
X		argc = 1;
X
X		while(i < strlen(tetrisenv) + 1) {
X
X			if(tetrisenv[i] == ' ' || tetrisenv[i] == '\0') {
X				buf[k] = '\0';
X				argv[++j] = (char *)malloc(100 * sizeof(char));
X				strcpy(argv[j], buf);
X				argc++;
X				i++;
X				k = 0;
X			}
X			else {
X				buf[k] = tetrisenv[i];
X				i++;
X				k++;
X			}
X		}
X	} else if(argc<2)
X		argv[1] = (char *)malloc(100 * sizeof(char *));
X	
X
X	/* process the arguments to the program */
X
X	while((c = getopt(argc, argv, "wtohnbsaL:N:O:K:")) != EOF) {
X		switch(c) {
X			case 'w':
X				nowrite = 1;
X				break;
X			case 'a':
X				addict = 1;
X				break;
X			case 't':
X				disp_tomb = 1;
X				break;
X			case 'o':
X				disp_open = 0;
X				break;
X			case 'h':
X				disp_high = 1;
X				break;
X			case 'n':
X				disp_next = 0;
X				break;
X			case 'b':
X				shadow = 0;
X				break;
X			case 's':
X				disp_score = 1;
X				break;
X			case 'N':
X				strcpy(username, optarg);
X				break;
X			case 'L':
X				level = (int)atoi(optarg);
X				if(level>20)
X					level = 20;
X				break;
X			case 'O':
X				rubble = (int)atoi(optarg);
X				if(rubble>13)
X					rubble = 13;
X				break;
X			case 'K':
X				if(strlen(optarg) == 7)
X					strcpy(keystr, optarg);
X				if(strlen(optarg) == 7)
X					break;
X			default:
X				fprintf(stderr, "Unknown flag or improper usage:\n");
X				fprintf(stderr, "\tuse '%s -' for usage\n", argv[0]);
X				exit(1);
X		}
X	}
X
X	if(!init_csr()) {
X		exit(1);
X	}
X
X	if(disp_score) {
X		display_high();
X		exit(0);
X	}
X
X	init_tetris();					/* inits stuff */
X
X	/* make unwritable */
X	if(nowrite & 1) {
X		ttystat->st_mode &= 495;
X		chmod(ttyname(0), ttystat->st_mode);
X	}
X
X	while (1) {						/* main loop, soon to be replaced */
X
X		while (read(0, &input, 1) == -1)	/* wait for input */
X			;
X
X		sprintf(argv[1], "%7.7d", points);
X
X		process_input(input); 				/* call to input processor */
X
X		SIGRELSE(14);						/* this is an attempt to fix a
X											   rare bug. ignore it     */
X
X	}
X}
X
X/*
X * Here's something you've all been waiting for:  the AT&T public domain
X * source for getopt (3).  It is the code which was given out at the 1985
X * UNIFORUM conference in Dallas.  I obtained it by electronic mail
X * directly from AT&T.  The people there assure me that it is indeed
X * in the public domain.
X * 
X * There is no manual page.  That is because the one they gave out at
X * UNIFORUM was slightly different from the current System V Release 2
X * manual page.  The difference apparently involved a note about the
X * famous rules 5 and 6, recommending using white space between an option
X * and its first argument, and not grouping options that have arguments.
X * Getopt itself is currently lenient about both of these things.  White
X * space is allowed, but not mandatory, and the last option in a group can
X * have an argument.  That particular version of the man page evidently
X * has no official existence, and my source at AT&T did not send a copy.
X * The current SVR2 man page reflects the actual behavor of this getopt.
X * However, I am not about to post a copy of anything licensed by AT&T.
X */
X
X/*LINTLIBRARY*/
X#define NULL	0
X#define EOF	(-1)
X#define ERR(s, c)	if (opterr){\
X	extern int write();\
X	char errbuf[2];\
X	errbuf[0] = c; errbuf[1] = '\n';\
X	(void) write (2, argv[0], (unsigned)strlen (argv[0]));\
X	(void) write (2, s, (unsigned)strlen (s));\
X	(void) write (2, errbuf, 2);}
X
Xextern char *index();
X
X
Xint getopt(argc, argv, opts)
Xint	argc;
Xchar	**argv, *opts;
X{
X	static int sp = 1;
X	register int c;
X	register char *cp;
X
X	if (sp == 1)
X		if (optind >= argc ||
X		   argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return (EOF);
X		else if (strcmp (argv[optind], "--") == NULL) {
X			optind++;
X			return (EOF);
X		}
X	optopt = c = argv[optind][sp];
X	if (c == ':' || (cp=index (opts, c)) == NULL) {
X		ERR (": illegal option -- ", c);
X		if (argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		return ('?');
X	}
X	if (*++cp == ':') {
X		if (argv[optind][sp+1] != '\0')
X			optarg = &argv[optind++][sp+1];
X		else if (++optind >= argc) {
X			ERR (": option requires an argument -- ", c);
X			sp = 1;
X			return ('?');
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if (argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return (c);
X}
END_OF_FILE
if test 7377 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'print_shape.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'print_shape.c'\"
else
echo shar: Extracting \"'print_shape.c'\" \(2128 characters\)
sed "s/^X//" >'print_shape.c' <<'END_OF_FILE'
X/*
X** written by adam margulies [email-masked]
X**                           {...}!ucbvax!ucscc!ssyx!vespa
X**
X** permission is granted to freely distribute this code provided that you:
X**
X** 1) don't charge for it
X** 2) leave my name and header on it
X** 3) clearly document your changes and place your name on them
X**
X*/
X/* Tetris: print_shape.c                                                  */
X/*                                                                        */
X/* this is the function that draws the shapes on the screen.              */
X/* Normally the shape is drawn using the color provided in the            */
X/* structure "shape". But calling this function with a color of ' '       */
X/* will effectively erase shapes as well.                                 */
X#include "tetris.h"
X
Xvoid print_shape(shape_number, x, y, rot, ch)
Xint shape_number, x, y, rot;
Xchar ch;
X{
X	if (y > 1) {
X		if (shape[shape_number].table[0][rot] & 8)
X			mvaddch(y,x,ch);
X		if (shape[shape_number].table[0][rot] & 4)
X			mvaddch(y,x+1,ch);
X		if (shape[shape_number].table[0][rot] & 2)
X			mvaddch(y,x+2,ch);
X		if (shape[shape_number].table[0][rot] & 1)
X			mvaddch(y,x+3,ch);
X	}
X
X	if (y > 0) {
X		if (shape[shape_number].table[1][rot] & 8)
X			mvaddch(y+1,x,ch);
X		if (shape[shape_number].table[1][rot] & 4)
X			mvaddch(y+1,x+1,ch);
X		if (shape[shape_number].table[1][rot] & 2)
X			mvaddch(y+1,x+2,ch);
X		if (shape[shape_number].table[1][rot] & 1)
X			mvaddch(y+1,x+3,ch);
X	}
X	if (y > -1) {
X		if (shape[shape_number].table[2][rot] & 8)
X			mvaddch(y+2,x,ch);
X		if (shape[shape_number].table[2][rot] & 4)
X			mvaddch(y+2,x+1,ch);
X		if (shape[shape_number].table[2][rot] & 2)
X			mvaddch(y+2,x+2,ch);
X		if (shape[shape_number].table[2][rot] & 1)
X			mvaddch(y+2,x+3,ch);
X	}
X
X	if (y > -2) {
X		if (shape[shape_number].table[3][rot] & 8)
X			mvaddch(y+3,x,ch);
X		if (shape[shape_number].table[3][rot] & 4)
X			mvaddch(y+3,x+1,ch);
X		if (shape[shape_number].table[3][rot] & 2)
X			mvaddch(y+3,x+2,ch);
X		if (shape[shape_number].table[3][rot] & 1)
X			mvaddch(y+3,x+3,ch);
X	}
X
X	if (ch != ' ' || fast_drop) 
X		csr_draw((y>2) ? y-1 : 2,x-3,y+4,x+7);
X}
END_OF_FILE
if test 2128 -ne `wc -c <'print_shape.c'`; then
    echo shar: \"'print_shape.c'\" unpacked with wrong size!
fi
# end of 'print_shape.c'
fi
if test -f 'process_input.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'process_input.c'\"
else
echo shar: Extracting \"'process_input.c'\" \(8156 characters\)
sed "s/^X//" >'process_input.c' <<'END_OF_FILE'
X/*
X** written by adam margulies [email-masked]
X**                           {...}!ucbvax!ucscc!ssyx!vespa
X**
X** permission is granted to freely distribute this code provided that you:
X**
X** 1) don't charge for it
X** 2) leave my name and header on it
X** 3) clearly document your changes and place your name on them
X**
X*/
X/* Tetris: process_input.c                                                  */
X/*                                                                          */
X/* This reads user input and calls funtions accordingly.                    */
X/* I used a series of if statements because case statements seemed          */
X/* too unwieldy for entries with long lists of code.                        */
X/*                                                                          */
X/* This function is also where all collision detection is done.             */
X/* The collision detection is quite ugly, but fast.                         */
X#include "tetris.h"
X
Xprocess_input(input)
Xchar input;
X{
X	void bfill(), redefine();
X	FILE *fp, *fopen();
X	int i=0,j=0,tmp_int = 0;
X	char tmp[81],c;
X
X	SIGHOLD(14);
X
X	if (input == 'S')   /* save game */
X		save_game();
X
X	if (input == 'D') {
X		redefine();
X		return;
X	}
X			
X	if (input == key->togdisp) {  /* toggle next block display */
X		print_shape(next->shape, 17, 6, next->rot, 
X				(disp_next ? ' ' : next->color));
X		csr_draw(6,17,9,20);
X		disp_next = !disp_next;
X		if (disp_next)
X			next->was_shown = 1;
X		SIGRELSE(14);
X		return;
X	}
X
X	if (input == key->togshad) { /* toggle shadowing */
X		shadow *= -1;
X		if (shadow == -1) {
X			mvaddstr(22,35,"----------");
X			csr_draw(22,35,22,45);
X		}
X		else {
X			draw_shadow();
X			current->was_shadowed = 0;
X		}
X		return;
X	}
X
X	if (input == '?') {  /* info */
X		
X		save_screen(0,0,23,79);
X		clear(0,0,23,79);
X
X		if ((fp = fopen(HELPFILE, "r")) == NULL){
X			SIGHOLD(14);
X			cls();
X			csr(23,0);
X			resetty();
X			fprintf(stderr, "%s\n", HELPFILE);
X			perror("opening help file");
X			exit(3);
X		}
X
X		flock(fileno(fp), LOCK_EX);
X		for(i=2;i<22;i++) {
X			while((c = fgetc(fp)) != '\n') 
X				tmp[j++]= c;
X			tmp[j] = '\0';
X			move(i,0);
X			printc("%s",tmp);
X			j = 0;
X		}
X		csr_draw(0,0,23,79);
X		csr(0,0);
X		getchar();
X		clear(2,0,22,79);
X		for(i=2;i<22;i++) {
X			while((c = fgetc(fp)) != '\n') 
X				tmp[j++]= c;
X			tmp[j] = '\0';
X			move(i,0);
X			printc("%s",tmp);
X			j = 0;
X		}
X		flock(fileno(fp), LOCK_UN);
X		fclose(fp);
X		csr_draw(2,0,22,79);
X		csr(0,0);
X
X		getchar();
X		restore_screen(0,0,23,79);
X		csr_draw(0,0,23,79);
X		SIGRELSE(14);
X		return;
X	}
X
X	if (input == 'P') {  /* pause */
X		save_screen(2,35,21,44);
X		
X		for(i=2;i<13;i++){
X			move(i,35);
X			printc("||||||||||");
X			csr_draw(i,35,i,44);
X
X			move(23-i,35);
X			printc("||||||||||");
X			csr_draw(23-i,35,23-i,44);
X		}
X			csr(12,35);
X			printf("  PAUSED  ");
X		csr(0,0);
X
X		getchar();
X
X		restore_screen(2,35,21,44);
X		csr_draw(2,35,21,44);
X		SIGRELSE(14);
X		return;
X	}
X
X	if (input == key->left && 	/* move block left, horiz collision detect */
X		( cury < 2 ||
X		!(shape[current->shape].table[0][current->rot] & (xoffset ? 4 : 8)
X		&& (window0[cury][curx-(xoffset ? 0 : 1)] != ' '))) &&
X
X		( cury < 1 ||
X		!(shape[current->shape].table[1][current->rot] & (xoffset ? 4 : 8)
X		&& (window0[cury+1][curx-(xoffset ? 0 : 1)] != ' '))) &&
X
X		( cury < 0 ||
X		!(shape[current->shape].table[2][current->rot] & (xoffset ? 4 : 8)
X		&& (window0[cury+2][curx-(xoffset ? 0 : 1)] != ' ')))) 
X
X		if(( cury < -1 ||
X		!(shape[current->shape].table[3][current->rot] & (xoffset ? 4 : 8)
X		&& (window0[cury+3][curx-(xoffset ? 0 : 1)] != ' ')))) 
X			if (curx + ( xoffset ? 1 : 0)
X				> 35 ) {
X
X				print_shape(current->shape,curx--, cury, current->rot, ' ');
X				print_shape(current->shape, curx, cury, current->rot,
X								current->color);
X				if (shadow == 1)
X					draw_shadow();
X
X				SIGRELSE(14);
X				return;
X			}
X							/* move block right, collision detect       */
X							/* this collision detection is more complex */
X	if (input == key->right && ((cury < 2) ||	
X		(!(shape[current->shape].table[0][current->rot] & 1
X		&& (window0[cury][curx+4] != ' ')) &&
X
X		!((shape[current->shape].table[0][current->rot] & 8 &&
X		!(shape[current->shape].table[0][current->rot] & 4)
X		&& (window0[cury][curx+1] != ' '))) &&
X
X		!((shape[current->shape].table[0][current->rot] & 2 &&
X		!(shape[current->shape].table[0][current->rot] & 1)
X		&& (window0[cury][curx+3] != ' '))) &&
X
X		!((shape[current->shape].table[0][current->rot] & 4 &&
X		!(shape[current->shape].table[0][current->rot] & 2)
X		&& (window0[cury][curx+2] != ' ')))))) 
X
X	if ((cury < 1) || 
X		(!(shape[current->shape].table[1][current->rot] & 1
X		&& (window0[cury+1][curx+4] != ' ')) &&
X
X		!((shape[current->shape].table[1][current->rot] & 4 &&
X		!(shape[current->shape].table[1][current->rot] & 2)
X		&& (window0[cury+1][curx+2] != ' '))) &&
X
X		!((shape[current->shape].table[1][current->rot] & 8 &&
X		!(shape[current->shape].table[1][current->rot] & 4)
X		&& (window0[cury+1][curx+1] != ' '))) &&
X
X		!((shape[current->shape].table[1][current->rot] & 2 &&
X		!(shape[current->shape].table[1][current->rot] & 1)
X		&& (window0[cury+1][curx+3] != ' ')))))
X
X	if ((cury < 0) ||
X		(!(shape[current->shape].table[2][current->rot] & 1
X		&& (window0[cury+2][curx+4] != ' ')) &&
X
X		!((shape[current->shape].table[2][current->rot] & 8 &&
X		!(shape[current->shape].table[2][current->rot] & 4)
X		&& (window0[cury+2][curx+1] != ' '))) &&
X
X		!((shape[current->shape].table[2][current->rot] & 2 &&
X		!(shape[current->shape].table[2][current->rot] & 1)
X		&& (window0[cury+2][curx+3] != ' '))) &&
X
X		!((shape[current->shape].table[2][current->rot] & 4 &&
X		!(shape[current->shape].table[2][current->rot] & 2)
X		&& (window0[cury+2][curx+2] != ' ')))))
X
X	if ((cury < -1) ||
X		(!(shape[current->shape].table[3][current->rot] & 1
X		&& (window0[cury+3][curx+4] != ' ')) &&
X
X		!((shape[current->shape].table[3][current->rot] & 2 &&
X		!(shape[current->shape].table[3][current->rot] & 1)
X		&& (window0[cury+3][curx+3] != ' '))) &&
X
X		!((shape[current->shape].table[3][current->rot] & 4 &&
X		!(shape[current->shape].table[3][current->rot] & 2)
X		&& (window0[cury+3][curx+2] != ' '))) &&
X
X		!((shape[current->shape].table[3][current->rot] & 8 &&
X		!(shape[current->shape].table[3][current->rot] & 4)
X		&& (window0[cury+3][curx+1] != ' '))))) 
X			if (curx + current->width < 45) {
X				print_shape(current->shape,curx++, cury, current->rot, ' ');
X				print_shape(current->shape, curx, cury, current->rot,
X								current->color);
X				if (shadow == 1)
X					draw_shadow();
X
X				SIGRELSE(14);
X				return;
X			}
X
X	if (input == key->rotright &&		/* rotate shape clockwise */
X		(curx + current->height < 46) &&
X		!(xoffset && curx < 36) &&
X		(cury + current->width < 22)
X		)
X		{
X			print_shape(current->shape, curx, cury, current->rot, ' ');
X			current->rot = ++current->rot % 4;
X			print_shape(current->shape, curx, cury, current->rot,
X						current->color);
X			tmp_int = current->height;
X			current->height = current->width;
X			current->width = tmp_int;
X			if (shadow == 1)
X				draw_shadow();
X
X			SIGRELSE(14);
X			return;
X		}
X
X	if (input == key->rotleft &&		/* rotate shape clockwise */
X		(curx + current->height < 46) &&
X		!(xoffset && curx < 35) &&
X		(cury + current->width < 22)
X		)
X		{
X
X			print_shape(current->shape, curx, cury, current->rot, ' ');
X			current->rot = (current->rot + 3) % 4;
X			print_shape(current->shape, curx, cury, current->rot,
X							current->color);
X			tmp_int = current->height;
X			current->height = current->width;
X			current->width = tmp_int;
X			if (shadow == 1)
X				draw_shadow();
X
X			SIGRELSE(14);
X			return;
X		}
X
X		if (input == key->drop) {	/* drop shape as fast as possible */
X
X			dropped_from = cury + current->height -1;
X			fast_drop = 1;
X
X			while (cury < 3)
X				drop_block();
X				
X			while(cury > 2)
X				drop_block();
X
X			dropped_from = 0;
X			fast_drop = 0;
X			SIGRELSE(14);
X			return;
X		}
X
X		if (input == 'Q') {		/*	quit   */
X			current->shape = 7;
X			end_game();
X		}
X		
X			/* changed '^R' to '\022'; [email-masked] */
X		if (input == '\022' || input == '\014') {
X			cls();
X			bfill(window0, sizeof(window0), ' ');
X			refresh();
X			SIGRELSE(14);
X			return;
X		}
X
X}
END_OF_FILE
if test 8156 -ne `wc -c <'process_input.c'`; then
    echo shar: \"'process_input.c'\" unpacked with wrong size!
fi
# end of 'process_input.c'
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