[comp.sources.games] v06i042: sun-tetris1 - tetris under SunView

games@tekred.CNA.TEK.COM (04/04/89)

Submitted-by: Rick Iwamoto <iwamoto@sun.com>
Posting-number: Volume 6, Issue 42
Archive-name: sun-tetris1

	[The other day I received two implementations of tetris under
	 SunView.  This is the first one.  They both use color (colour)
	 on machines that support it.  I have tested them both on a B&W
	 Sun 3/60, SunOS 3.5. The second one follows in the next posting. -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 1)."
# Contents:  README Makefile suntetris.6 suntetris.c suntetris.h
#   suntetris.icon suntetris_pw.c
# Wrapped by billr@saab on Mon Apr  3 13:11:41 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'\" \(2204 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
X
X
X
X				SUNTETRIS
X
X
XTo install, change the highscore filename in the Makefile and type "make".
X
X
XPlaying the game
X----------------
X
XSelecting the level and height of random blocks:
X
X    Use the '0'-'9' keys, the cursor keys, or 'h', 'j', 'k', 'l' as in "vi"
X    to select the level, hit "return"
X    Select the height, and hit "return" to begin the game.
X
X
XThe game controls:
X
X    'j' R10 or the left mouse button makes the figure shift left
X
X    'k' R11 or the middle mouse button makes the figure rotate
X	(counter clockwise)
X
X    'l' R12 or the right mouse button makes the figure shift right
X
X    spacebar or R14 makes the figure drop down
X
X    'u' or R8 increases level
X
X    'q' quits the game at any time
X
X    When your cursor leaves the window, the game will pause.
X    When your cursor enters the window, the game will resume.
X
XWhen the game ends, the high scores are displayed until the "return" key
Xis pressed.
X
X
XNote:
XIn order to use the R(n) keys (the cursor keys), they must be emitting Sunview
Xfunction codes, not ANSI escape sequences.  This can be changed by using
Xdefaultsedit and selecting the "Input" menu.
X
X
X
XThe Game
X--------
X
XDifferent shaped figures fall from the top of the playing area to the bottom,
Xwhere they come to rest.  When a figure comes to rest and it completes a solid
Xrow of blocks across the playing area, the row disappears and everything above
Xit shifts down.  The game ends when the figures pile up to the very top of the
Xplaying area.
X
XThe object of the game is to manuever the falling figure by moving it left,
Xright, and by rotating it to avoid having the figures pile up too high.  A
Xfigure may be dropped to a resting position at any time for more points.  Your
Xscore depends on the current level and the height at which the figure lands
Xor is dropped from.  The level (speed) increases when the number of rows
Xdeleted reaches certain levels.
X
X
X
XComments
X--------
X
XI tried to make this look and feel exactly like the PC version, with the
Xexception of the different background pictures and the "Next block" indicator,
Xwhich didn't work on the PC version that I saw.  The scoring system may
Xnot be the same.
X
X
XReport any bugs to iwamoto@sun.com.
X
X-Rick Iwamoto
END_OF_FILE
if test 2204 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(453 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# @(#)Makefile	1.5 3/22/89
XOBJS = suntetris.o suntetris_pw.o
XCFLAGS = -O
XLIBS = -lsuntool -lsunwindow -lpixrect
X
X# Change this to desired highscore file before compiling
X# i.e. "/usr/games/suntetris.hs"
XHIGHSCOREFILE = /usr/net/games/lib/suntetris.hs
X
Xsuntetris: $(OBJS)
X	cc $(CFLAGS) $(OBJS) -o suntetris $(LIBS)
X
Xsuntetris.o: suntetris.h
X
Xsuntetris_pw.o: suntetris.h suntetris_pw.c
X	cc $(CFLAGS) -c -DHIGHSCOREFILE=\"$(HIGHSCOREFILE)\" suntetris_pw.c
END_OF_FILE
if test 453 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'suntetris.6' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'suntetris.6'\"
else
echo shar: Extracting \"'suntetris.6'\" \(2146 characters\)
sed "s/^X//" >'suntetris.6' <<'END_OF_FILE'
X.TH SUNTETRIS 6
X.SH NAME
Xsuntetris - tetris for SunView
X.SH SYNOPSIS
Xsuntetris [bw]
X.SH DESCRIPTION
X.SS Options
XIf any arguments are supplied, black and white rendition is forced
X(applies to color monitors only).
X.SS Playing the game
X.LP
XSelecting the level and height of random blocks:
X.IP
XUse the '0'-'9' keys, the cursor keys, or 'h', 'j', 'k', 'l' as in "vi"
Xto select the level, hit "return".
XSelect the height using cursor keys or hjkl, and hit "return" to begin
Xthe game.
X.LP
XThe game controls:
X.IP
X\&'j' R10 or the left mouse button makes the figure shift left
X.IP
X\&'k' R11 or the middle mouse button makes the figure rotate
X(counter clockwise)
X.IP
X\&'l' R12 or the right mouse button makes the figure shift right
X.IP
Xspacebar or R14 makes the figure drop down
X.IP
X\&'u' or R8 increases level
X.IP
X\&'q' quits the game at any time
X.IP
XWhen your cursor leaves the window, the game will pause.
XWhen your cursor enters the window, the game will resume.
X.LP
XWhen the game ends, the high scores are displayed until the "return" key
Xis pressed.
X.SS The Game
X.LP
XDifferent shaped figures fall from the top of the playing area to the bottom,
Xwhere they come to rest.  When a figure comes to rest and it completes a solid
Xrow of blocks across the playing area, the row disappears and everything above
Xit shifts down.  The game ends when the figures pile up to the very top of the
Xplaying area.
X.LP
XThe object of the game is to manuever the falling figure by moving it left,
Xright, and by rotating it to avoid having the figures pile up too high.  A
Xfigure may be dropped to a resting position at any time for more points.  Your
Xscore depends on the current level and the height at which the figure lands
Xor is dropped from.  The level (speed) increases when the number of rows
Xdeleted reaches certain levels.
X.SH FILES
Xsuntetris.hs - high score file
X.SH AUTHOR
XRick Iwamoto (iwamoto@sun.com).
X.SH COMMENTS
XI tried to make this look and feel exactly like the PC version, with the
Xexception of the different background pictures and the "Next block" indicator,
Xwhich didn't work on the PC version that I saw.  The scoring system may
Xnot be the same.
END_OF_FILE
if test 2146 -ne `wc -c <'suntetris.6'`; then
    echo shar: \"'suntetris.6'\" unpacked with wrong size!
fi
# end of 'suntetris.6'
fi
if test -f 'suntetris.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'suntetris.c'\"
else
echo shar: Extracting \"'suntetris.c'\" \(9581 characters\)
sed "s/^X//" >'suntetris.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char sccsid[] = "@(#)suntetris.c	1.17 3/23/89";
X#endif
X
X/*
X *  Copyright 1989, Rick Iwamoto iwamoto@sun.com
X *  Permission is given to copy and distribute for non-profit purposes.
X */
X
X#include <stdio.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include "suntetris.h"
X
Xstatic short icon_image[] = {
X#include "suntetris.icon"
X};
XDEFINE_ICON_FROM_IMAGE (tetris_icon, icon_image);
X
XCanvas canvas;
X
Xstatic int my_client_object;
Xstatic int *me = &my_client_object;
Xstatic int paused = 0, selht = 0, height = 0;
Xstatic int level, lines, score, make_new_fig;
Xstatic int current_color, current_fig, current_rot, current_x, current_y;
Xstatic struct itimerval timer;
X
Xvoid init_pw (), draw_board (), rand_blocks (), draw_figure (), draw_score ();
Xvoid close_board (), display_choices (), display_hs (), update_hs ();
Xvoid select_level (), select_height ();
Xvoid mark_board ();
Xint safe_move ();
X
Xstatic Notify_value figure_dropper ();
Xstatic void new_figure (), place_figure ();
Xstatic void game_setup (), start_game (), game_over (), drop_down ();
Xstatic void start_timer (), stop_timer ();
Xstatic void game_control_proc (), choose_level ();
Xstatic void choose_height (), wait_for_return ();
X
X
X/*
X    4 canvas input event routines
X
X    1) choose_level ()
X	player chooses level to start at
X    2) choose_height ()
X	player chooses height to start at
X    3) game_control_proc ()
X	game controls (move blocks around etc.)
X    4) wait_for_return ()
X	game waits for player to hit return while displaying highscores
X*/
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X    Frame frame;
X
X    frame = window_create (0, FRAME,
X		FRAME_LABEL, argv[0],
X		FRAME_ICON, &tetris_icon,
X	    0);
X    canvas = window_create (frame, CANVAS,
X		 CANVAS_RETAINED, FALSE,
X		 WIN_WIDTH, 400,
X		 WIN_HEIGHT, 400,
X		 WIN_CONSUME_PICK_EVENT, WIN_IN_TRANSIT_EVENTS,
X		 WIN_CONSUME_KBD_EVENTS, WIN_ASCII_EVENTS, WIN_RIGHT_KEYS, 0,
X	     0);
X    window_fit (frame);
X    init_pw (argc > 1);	/* force b&w operation if any arguments exist */
X    window_set (canvas, CANVAS_RETAINED, TRUE, 0);
X    srandom (getpid ());
X
X    game_setup ();
X    window_main_loop (frame);
X}
X
X
X/* figure_dropper does the periodic downward moving of the figures */
Xstatic Notify_value
Xfigure_dropper (me, which)
XNotify_client me;
Xint which;
X{
X    /* if next position is unoccupied, move the figure down by 1 */
X    if (safe_move (current_fig, current_rot, current_x, current_y+1))  {
X	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
X		     current_y*BLOCKSIZE+BOARD_Y, BLACK);
X	current_y++;
X	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
X		     current_y*BLOCKSIZE+BOARD_Y, current_color);
X    }
X    else if (current_y < 0)  game_over ();	/* all over when at the top */
X    else if (make_new_fig)  {
X	make_new_fig = 0;
X	place_figure ();	/* the figure comes to rest */
X	new_figure ();		/* start a new one */
X    }
X    else  {
X	make_new_fig = 1;
X    }
X}
X
X
X/* drop_down drops the figure down as far as it can go without hitting
X   other blocks along the way */
Xstatic void
Xdrop_down ()
X{
X    int new_y = current_y;
X
X    while (safe_move (current_fig, current_rot, current_x, new_y+1))  new_y++;
X    if (new_y < 0)  {
X	game_over ();
X	return;
X    }
X    score += BOARDHEIGHT-(current_y+2);	/* bonus for dropping */
X    draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
X		 current_y*BLOCKSIZE+BOARD_Y, BLACK);
X    current_y = new_y;
X    draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
X		 current_y*BLOCKSIZE+BOARD_Y, current_color);
X    place_figure ();	/* rest the figure */
X    new_figure ();	/* start a new one */
X}
X
X
Xstatic void
Xgame_over ()
X{
X    stop_timer ();
X    window_set (canvas, WIN_EVENT_PROC, wait_for_return, 0);
X    close_board ();
X    update_hs (score, level);
X    display_hs ();
X}
X
X
X/* this select delay stuff doesn't work all that well, but it's sufficient */
Xstatic struct timeval delay_1sec = { 0, 999999 };
X
X/* place the figure at its resting spot, update scores, do any reducing
X   of rows */
Xstatic void
Xplace_figure ()
X{
X    stop_timer ();
X    score += 2*level + BOARDHEIGHT-(current_y+2) + 5;
X    mark_board (current_fig, current_rot, current_x, current_y);
X    lines += reduce_rows (current_y);
X    if (level < MAXLEVEL && lines > 10*(level+1))  {
X	level++;	/* should pause for a sec */
X	select (1, 0, 0, 0, &delay_1sec);
X    }
X    draw_score (lines, score, level);
X    if (!paused)  start_timer ();
X}
X
X
X/* new_figure generates a new random figure */
Xstatic void
Xnew_figure ()
X{
X    current_x = 3;
X    current_y = -1;
X    current_rot = 0;
X    current_fig = random () % 7;
X    current_color = current_fig + 1;
X    draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
X		 current_y*BLOCKSIZE+BOARD_Y, current_color);
X}
X
X
X/*
X * The cursor left (R10), 'j', and the left mouse button cause the block to
X * move left.  R11, 'k', and the middle mouse button cause the block to
X * rotate counter-clockwise.  The cursor right (R12), 'l', and the right
X * mouse button cause the block to move right.  The cursor down (R14) and
X * the spacebar cause the block to drop down to the bottom.
X * The Cursor keys must not be emitting escape sequences (SunView Defaults)
X */
Xstatic void
Xgame_control_proc (canvas, event)
XCanvas canvas;
XEvent *event;
X{
X    int new_x = current_x;
X    int new_rot = current_rot;
X
X    if (event_is_button (event) && event_is_up (event))  return;
X    switch (event_id (event))  {
X	case 'q':
X	    exit (0);
X	case MS_LEFT:
X	case 'j':
X	case KEY_RIGHT(10):	/* LEFT */
X	    new_x = current_x - 1;
X	    break;
X	case MS_MIDDLE:
X	case 'k':
X	case KEY_RIGHT(11):	/* ROTATE */
X	    new_rot = (current_rot + 1) % 4;
X	    break;
X	case MS_RIGHT:
X	case 'l':
X	case KEY_RIGHT(12):	/* RIGHT */
X	    new_x = current_x + 1;
X	    break;
X	case ' ':
X	case KEY_RIGHT(14):	/* DOWN */
X	    drop_down ();
X	    return;
X	    break;
X	case 'u':
X	case KEY_RIGHT(8):	/* UP LEVEL */
X	    if (level < MAXLEVEL)  {
X		level++;
X		stop_timer ();
X		select (1, 0, 0, 0, &delay_1sec);
X		draw_score (lines, score, level);
X		start_timer ();
X	    }
X	    return;
X	    break;
X	case LOC_WINENTER:
X	case LOC_RGNENTER:
X	    start_timer ();
X	    paused = 0;
X	    return;
X	case LOC_WINEXIT:
X	case LOC_RGNEXIT:
X	    stop_timer ();
X	    paused = 1;
X	    return;
X	default:
X	    return;
X	    break;
X    }
X    if (safe_move (current_fig, new_rot, new_x, current_y))  {
X	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
X		     current_y*BLOCKSIZE+BOARD_Y, BLACK);
X	current_rot = new_rot;
X	current_x = new_x;
X	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
X		     current_y*BLOCKSIZE+BOARD_Y, current_color);
X    }
X}
X
X
X#define ITIMER_NULL ((struct itimerval *) 0)
X
Xstatic void
Xstart_timer ()
X{
X    timer.it_interval.tv_usec = (11-level)*50000;
X    timer.it_interval.tv_sec = 0;
X    timer.it_value.tv_usec = (11-level)*50000;
X    timer.it_value.tv_sec = 0;
X    (void) notify_set_itimer_func (me, figure_dropper,
X	ITIMER_REAL, &timer, ITIMER_NULL);
X}
X
X
Xstatic void
Xstop_timer ()
X{
X    /* turn off timer */
X    notify_set_itimer_func (me, figure_dropper, ITIMER_REAL, ITIMER_NULL,
X	ITIMER_NULL);
X}
X
X
Xstatic void
Xstart_game ()
X{
X    lines = 0;
X    score = 0;
X    make_new_fig = 0;
X    draw_board ();
X    draw_score (lines, score, level);
X    rand_blocks (height);
X    window_set (canvas, WIN_EVENT_PROC, game_control_proc, 0);
X    new_figure ();
X    start_timer ();
X}
X
X
Xstatic void
Xchoose_level (canvas, event)
XCanvas canvas;
XEvent *event;
X{
X    switch (event_id (event))  {
X	case '0':
X	case '1':
X	case '2':
X	case '3':
X	case '4':
X	case '5':
X	case '6':
X	case '7':
X	case '8':
X	case '9':
X	    select_level (level);
X	    level = event_id (event) - '0';
X	    select_level (level);
X	    break;
X	case 'q':
X	    exit (0);
X	case 'h':
X	case KEY_RIGHT(10):	/* LEFT */
X	    select_level (level);
X	    level = (level + 9) % 10;
X	    select_level (level);
X	    break;
X	case 'l':
X	case KEY_RIGHT(12):	/* RIGHT */
X	    select_level (level);
X	    level = (level + 1) % 10;
X	    select_level (level);
X	    break;
X	case 'k':
X	case KEY_RIGHT(8):	/* UP */
X	case 'j':
X	case KEY_RIGHT(14):	/* DOWN */
X	    select_level (level);
X	    level = (level + 5) % 10;
X	    select_level (level);
X	    break;
X	case '\015':		/* RETURN */
X	    selht = 0;
X	    select_height (selht);
X	    window_set (canvas, WIN_EVENT_PROC, choose_height, 0);
X	    break;
X    }
X}
X
X
Xstatic void
Xchoose_height (canvas, event)
XCanvas canvas;
XEvent *event;
X{
X    switch (event_id (event))  {
X	case 'q':
X	    exit (0);
X	case 'h':
X	case KEY_RIGHT(10):	/* LEFT */
X	    select_height (selht);
X	    selht = (selht + 5) % 6;
X	    select_height (selht);
X	    break;
X	case 'l':
X	case KEY_RIGHT(12):	/* RIGHT */
X	    select_height (selht);
X	    selht = (selht + 1) % 6;
X	    select_height (selht);
X	    break;
X	case 'k':
X	case KEY_RIGHT(8):	/* UP */
X	case 'j':
X	case KEY_RIGHT(14):	/* DOWN */
X	    select_height (selht);
X	    selht = (selht + 3) % 6;
X	    select_height (selht);
X	    break;
X	case '\015':		/* RETURN */
X	    switch (selht)  {
X		case 0: height = 0; break;
X		case 1: height = 4; break;
X		case 2: height = 7; break;
X		case 3: height = 10; break;
X		case 4: height = 13; break;
X	    }
X	    start_game ();
X	    break;
X    }
X}
X
X
Xstatic void
Xwait_for_return (canvas, event)
XCanvas canvas;
XEvent *event;
X{
X    switch (event_id (event))  {
X	case 'q':  exit (0);
X	case '\015':
X	    game_setup ();
X	    break;
X    }
X}
X
X	    
Xstatic void
Xgame_setup ()
X{
X    display_choices ();
X    window_set (canvas, WIN_EVENT_PROC, choose_level, 0);
X    level = 5;
X    select_level (level);
X}
END_OF_FILE
if test 9581 -ne `wc -c <'suntetris.c'`; then
    echo shar: \"'suntetris.c'\" unpacked with wrong size!
fi
# end of 'suntetris.c'
fi
if test -f 'suntetris.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'suntetris.h'\"
else
echo shar: Extracting \"'suntetris.h'\" \(1088 characters\)
sed "s/^X//" >'suntetris.h' <<'END_OF_FILE'
X/* @(#)suntetris.h	1.9 3/22/89 */
X/*
X *  Copyright 1989, Rick Iwamoto iwamoto@sun.com
X *  Permission is given to copy and distribute for non-profit purposes. 
X */
X
X#define MAXLEVEL 9
X#define BOARDWIDTH 10
X#define BOARDHEIGHT 20
X#define BOARD_X 200
X#define BOARD_Y 50
X#define BLOCKSIZE 16
X#define SCREENDEPTH 8
X#define SCORE_Y BOARD_Y+50
X#define LINES_Y BOARD_Y+100
X#define LEVEL_Y BOARD_Y+150
X#define TETRISCMSSIZE 16
X
X#define	BLACK	0
X#define	RED	1
X#define	YELLOW	2
X#define	LTGREEN	3
X#define	GREEN	4
X#define	BLUE	5
X#define	VIOLET	6
X#define	CYAN	7
X#define	WHITE	15
X
X#define	tetris_cms(r,g,b) \
X	(r)[BLACK] = 0;		(g)[BLACK] = 0;		(b)[BLACK] = 0; \
X	(r)[RED] = 255;		(g)[RED] = 0;		(b)[RED] = 0; \
X	(r)[YELLOW] = 255;	(g)[YELLOW] = 255;	(b)[YELLOW] = 0; \
X	(r)[LTGREEN] = 180;	(g)[LTGREEN] = 255;	(b)[LTGREEN] = 180; \
X	(r)[GREEN] = 0;		(g)[GREEN] = 255;	(b)[GREEN] = 0; \
X	(r)[BLUE] = 0;		(g)[BLUE] = 0;		(b)[BLUE] = 255; \
X	(r)[VIOLET] = 255;	(g)[VIOLET] = 0;	(b)[VIOLET] = 255; \
X	(r)[CYAN] = 0;		(g)[CYAN] = 255;	(b)[CYAN] = 255; \
X	(r)[WHITE] = 255;	(g)[WHITE] = 255;	(b)[WHITE] = 255;
END_OF_FILE
if test 1088 -ne `wc -c <'suntetris.h'`; then
    echo shar: \"'suntetris.h'\" unpacked with wrong size!
fi
# end of 'suntetris.h'
fi
if test -f 'suntetris.icon' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'suntetris.icon'\"
else
echo shar: Extracting \"'suntetris.icon'\" \(1933 characters\)
sed "s/^X//" >'suntetris.icon' <<'END_OF_FILE'
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x8000,0x0000,0x0000,0x0001,
X	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
X	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBF81,0xFFFF,0xFFFF,0xFFFD,
X	0xBFA5,0xFFFF,0xFFFF,0xFFFD,0xBFE7,0xFFFF,0xFFFF,0xFFFD,
X	0xBFE7,0xFFFF,0xFFFF,0xFFFD,0xBFE7,0xFFFF,0xFFFF,0xFFFD,
X	0xBFC3,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
X	0xBFFF,0xFFFF,0xFFF0,0xFFFD,0xBF81,0xFFFF,0xFFF0,0xFFFD,
X	0xBFDD,0xFFFF,0xFFF0,0xFFFD,0xBFC7,0xFFFF,0xFFF0,0xFFFD,
X	0xBFDF,0xFFFF,0xFF00,0xFFFD,0xBFDD,0xFFFF,0xFF00,0xFFFD,
X	0xBF81,0xFFFF,0xFF00,0xFFFD,0xBFFF,0xFFFF,0xFF00,0xFFFD,
X	0xBFFF,0xFFFF,0xFF0F,0xFFFD,0xBF81,0xFFFF,0xFF0F,0xFFFD,
X	0xBFA5,0xFFFF,0xFF0F,0xFFFD,0xBFE7,0xFFFF,0xFF0F,0xFFFD,
X	0xBFE7,0xFFFF,0xFFFF,0xFFFD,0xBFE7,0xFFFF,0xFFFF,0xFFFD,
X	0xBFC3,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
X	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBF83,0xFFFF,0xFFFF,0xFFFD,
X	0xBFD9,0xFFFF,0xFFFF,0xFFFD,0xBFD9,0xFFFF,0xFFFF,0xFFFD,
X	0xBFC3,0xFFFF,0xFFFF,0xFFFD,0xBFDB,0xFFFF,0xFFFF,0xFFFD,
X	0xBF99,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
X	0xBFFF,0xFFFF,0xFFFF,0xFF8D,0xBFC3,0xFFFF,0xFFFF,0xFF8D,
X	0xBFE7,0xFFFF,0xFFFF,0xFF2D,0xBFE7,0xFFFF,0xFFFF,0xFF2D,
X	0xBFE7,0xFFFF,0xFFFF,0xFF8D,0xBFE7,0xFFFF,0xFFFF,0xFF8D,
X	0xBFC3,0xFFFF,0xFFFF,0xFF2D,0xBFFF,0xFFFF,0xFFFF,0xFF2D,
X	0xBFFF,0xFF87,0x7FFF,0xFF8D,0xBFC1,0xFF8D,0xDFFF,0xFF8D,
X	0xBF9D,0xFF2B,0xBFFF,0xFF2D,0xBF87,0xFF2E,0xEFFF,0xFF2D,
X	0xBFE1,0xF88A,0x77FF,0xAF8D,0xBFB9,0xF885,0xDDFF,0x5F8D,
X	0xBF83,0xF22A,0xBBFF,0xAF2D,0xBFFF,0xF225,0xEEFF,0x5F2D,
X	0xBFFF,0xF08A,0xAAFF,0xA88D,0xBFFF,0xF085,0x55FF,0x522D,
X	0xBFFF,0xF02A,0xAAFF,0xA44D,0xBFFF,0xF025,0x55FF,0x511D,
X	0xBFFF,0xF088,0x88FA,0xA88D,0xBFFF,0xF022,0x22F5,0x522D,
X	0xBFFF,0xF044,0x44FA,0xA44D,0xBFFF,0xF011,0x11F5,0x511D,
X	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
X	0x8000,0x0000,0x0000,0x0001,0xFFFF,0xFFFF,0xFFFF,0xFFFF
END_OF_FILE
if test 1933 -ne `wc -c <'suntetris.icon'`; then
    echo shar: \"'suntetris.icon'\" unpacked with wrong size!
fi
# end of 'suntetris.icon'
fi
if test -f 'suntetris_pw.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'suntetris_pw.c'\"
else
echo shar: Extracting \"'suntetris_pw.c'\" \(15955 characters\)
sed "s/^X//" >'suntetris_pw.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char sccsid[] = "@(#)suntetris_pw.c	1.14 3/23/89";
X#endif
X/*
X *  Copyright 1989, Rick Iwamoto iwamoto@sun.com
X *  Permission is given to copy and distribute for non-profit purposes. 
X */
X
X#include <stdio.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include "suntetris.h"
X#include <pwd.h>
X#include <unistd.h>
X
Xextern Canvas canvas;
Xstatic Pixwin *pw;
Xstatic Pixfont *bigfont;
Xstatic Pixrect *savepr;
Xstatic int incolor;
Xstatic int boardmap[BOARDWIDTH][BOARDHEIGHT];
X
Xtypedef
Xstruct figure  {
X    int x[4], y[4];
X} Figure;
X
Xstatic Figure fig1a = { { 2, 1, 0, 0 }, { 2, 2, 2, 1 } };
Xstatic Figure fig1b = { { 1, 1, 1, 0 }, { 0, 1, 2, 2 } };
Xstatic Figure fig1c = { { 0, 1, 2, 2 }, { 1, 1, 1, 2 } };
Xstatic Figure fig1d = { { 1, 1, 1, 2 }, { 2, 1, 0, 0 } };
Xstatic Figure fig2a = { { 0, 1, 2, 2 }, { 2, 2, 2, 1 } };
Xstatic Figure fig2b = { { 1, 1, 1, 0 }, { 2, 1, 0, 0 } };
Xstatic Figure fig2c = { { 2, 1, 0, 0 }, { 1, 1, 1, 2 } };
Xstatic Figure fig2d = { { 1, 1, 1, 2 }, { 0, 1, 2, 2 } };
Xstatic Figure fig3a = { { 0, 1, 2, 1 }, { 2, 2, 2, 1 } };
Xstatic Figure fig3b = { { 1, 1, 1, 0 }, { 2, 1, 0, 1 } };
Xstatic Figure fig3c = { { 2, 1, 0, 1 }, { 1, 1, 1, 2 } };
Xstatic Figure fig3d = { { 1, 1, 1, 2 }, { 0, 1, 2, 1 } };
Xstatic Figure fig4a = { { 0, 1, 1, 2 }, { 1, 1, 2, 2 } };
Xstatic Figure fig4b = { { 1, 1, 2, 2 }, { 2, 1, 1, 0 } };
Xstatic Figure fig5a = { { 0, 1, 1, 2 }, { 2, 2, 1, 1 } };
Xstatic Figure fig5b = { { 2, 2, 1, 1 }, { 2, 1, 1, 0 } };
Xstatic Figure fig6a = { { 0, 1, 2, 3 }, { 1, 1, 1, 1 } };
Xstatic Figure fig6b = { { 2, 2, 2, 2 }, { 3, 2, 1, 0 } };
Xstatic Figure fig7 = { { 0, 1, 0, 1 }, { 1, 1, 2, 2 } };
X
X
Xstatic Figure *figures[7][4] = {
X    { &fig1a, &fig1b, &fig1c, &fig1d },	/* backward L */
X    { &fig2a, &fig2b, &fig2c, &fig2d },	/* L */
X    { &fig3a, &fig3b, &fig3c, &fig3d },	/* T */
X    { &fig4a, &fig4b, &fig4a, &fig4b },	/* Z */
X    { &fig5a, &fig5b, &fig5a, &fig5b },	/* S */
X    { &fig6a, &fig6b, &fig6a, &fig6b },	/* I */
X    { &fig7, &fig7, &fig7, &fig7 }	/* Square block */
X};
X
X
Xstatic bordercolor[8] =
X    { BLACK, GREEN, LTGREEN, VIOLET, RED, BLUE, YELLOW, CYAN };
Xstatic fillcolor[8] =
X    { BLACK, RED, GREEN, RED, BLACK, VIOLET, RED, WHITE };
X
Xstatic short bwdata0[] = {	/* BLACK */
X    0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
X    0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
X};
Xmpr_static (bwblock0, BLOCKSIZE, BLOCKSIZE, 1, bwdata0);
Xstatic short bwdata1[] = {	/* root middle */
X	0x0000,0x0000,0x2220,0x2220,0x0888,0x0888,0x2220,0x2220,
X	0x0888,0x0888,0x2220,0x2220,0x0888,0x0888,0x0000,0x0000
X};
Xmpr_static (bwblock1, BLOCKSIZE, BLOCKSIZE, 1, bwdata1);
Xstatic short bwdata2[] = {	/* 25 % middle */
X	0x0000,0x0000,0x0444,0x1110,0x0888,0x2220,0x0444,0x1110,
X	0x0888,0x2220,0x0444,0x1110,0x0888,0x2220,0x0000,0x0000
X};
Xmpr_static (bwblock2, BLOCKSIZE, BLOCKSIZE, 1, bwdata2);
Xstatic short bwdata3[] = {	/* 50 % middle */
X	0x0000,0x0000,0x2AA8,0x1554,0x2AA8,0x1554,0x2AA8,0x1554,
X	0x2AA8,0x1554,0x2AA8,0x1554,0x2AA8,0x1554,0x0000,0x0000
X};
Xmpr_static (bwblock3, BLOCKSIZE, BLOCKSIZE, 1, bwdata3);
Xstatic short bwdata4[] = {	/* 75 % middle */
X	0x0000,0x0000,0x3BB8,0x2EEC,0x3774,0x1DDC,0x3BB8,0x2EEC,
X	0x3774,0x1DDC,0x3BB8,0x2EEC,0x3774,0x1DDC,0x0000,0x0000
X};
Xmpr_static (bwblock4, BLOCKSIZE, BLOCKSIZE, 1, bwdata4);
Xstatic short bwdata5[] = {	/* horiz middle */
X	0x0000,0x0000,0x3FFC,0x0000,0x3FFC,0x0000,0x3FFC,0x0000,
X	0x3FFC,0x0000,0x3FFC,0x0000,0x3FFC,0x0000,0x0000,0x0000
X};
Xmpr_static (bwblock5, BLOCKSIZE, BLOCKSIZE, 1, bwdata5);
Xstatic short bwdata6[] = {	/* diag middle */
X	0x0000,0x0000,0x2490,0x1248,0x0924,0x2490,0x1248,0x0924,
X	0x2490,0x1248,0x0924,0x2490,0x1248,0x0924,0x0000,0x0000
X};
Xmpr_static (bwblock6, BLOCKSIZE, BLOCKSIZE, 1, bwdata6);
Xstatic short bwdata7[] = {	/* checker middle */
X	0x0000,0x0000,0x3330,0x3330,0x0CCC,0x0CCC,0x3330,0x3330,
X	0x0CCC,0x0CCC,0x3330,0x3330,0x0CCC,0x0CCC,0x0000,0x0000
X};
Xmpr_static (bwblock7, BLOCKSIZE, BLOCKSIZE, 1, bwdata7);
Xstatic Pixrect *bwblocks[8] = {
X    &bwblock0, &bwblock1, &bwblock2, &bwblock3, 
X    &bwblock4, &bwblock5, &bwblock6, &bwblock7
X};
X
X#define BORDER 2
X
X/* draw_block draws a single block according to color or black&white mode */
X#define draw_block(x,y,color) { \
X    if (incolor)  { \
X	pw_rop (pw, (x), (y), BLOCKSIZE, BLOCKSIZE, \
X	    PIX_SRC | PIX_COLOR(bordercolor[color]), 0, 0, 0); \
X	pw_rop (pw, (x)+BORDER, (y)+BORDER, \
X	    BLOCKSIZE-2*BORDER, BLOCKSIZE-2*BORDER, \
X	    PIX_SRC | PIX_COLOR(fillcolor[color]), 0, 0, 0); \
X    } else \
X	pw_rop (pw, (x), (y), BLOCKSIZE, BLOCKSIZE, \
X	    PIX_NOT(PIX_SRC), bwblocks[color], 0, 0); \
X    }
X    
X
X/* draw_figure draws one of the 7 figures in the specified orientation
X   at the location on the canvas */
Xvoid
Xdraw_figure (figno, orientation, pix_x, pix_y, color)
Xint figno, orientation, pix_x, pix_y, color;
X{
X    int i;
X
X    if (figno > 6 || orientation > 3)  exit (1);
X    pw_batch_on (pw);
X    for (i = 0; i < 4; i++)
X	draw_block (pix_x+(figures[figno][orientation]->x[i])*BLOCKSIZE,
X	    pix_y+(figures[figno][orientation]->y[i])*BLOCKSIZE, color)
X    pw_batch_off (pw);
X}
X
X
X/* safe_move tells when the block will collide with another or when it
X   is at the border of the board */
Xsafe_move (figno, orientation, x, y)
Xint figno, orientation, x, y;
X{
X    int i, xpos, ypos;
X
X    for (i = 0; i < 4; i++)  {
X	xpos = x+figures[figno][orientation]->x[i];
X	ypos = y+figures[figno][orientation]->y[i];
X	if (xpos < 0 || xpos >= BOARDWIDTH || ypos < 0 || ypos >= BOARDHEIGHT
X	    || boardmap[xpos][ypos] != 0)  return (0);
X    }
X    return (1);
X}
X
X
X/* mark_board logs the specified figure on the boardmap, which keeps track
X   of all pieces which have come to rest */
Xvoid
Xmark_board (figno, orientation, x, y)
Xint figno, orientation, x, y;
X{
X    int i, xpos, ypos;
X
X    for (i = 0; i < 4; i++)  {
X	xpos = x+figures[figno][orientation]->x[i];
X	ypos = y+figures[figno][orientation]->y[i];
X	boardmap[xpos][ypos] = 1;
X    }
X}
X
X
Xstatic struct timeval delay_50ms = { 0, 50000 };
X
X/* reduce_rows checks for solid blocks across rows on the board,
X   flashes the rows to be deleted, then deletes them from the board
X   as well as the boardmap */
Xreduce_rows (y)
Xint y;
X{
X    int i, j, skip = 0, reducing = 0;
X    static int reduce[BOARDHEIGHT] = {
X    	0, 0, 0, 0, 0,
X    	0, 0, 0, 0, 0,
X    	0, 0, 0, 0, 0,
X    	0, 0, 0, 0, 0 };
X
X    /* check for solid rows */
X    /* log all of the rows which need to be deleted into reduce[] */
X    /* At most 4 rows can be deleted at one time */
X    for (j = y+3; j >= y; j--)  {
X	if (j >= BOARDHEIGHT)  continue;
X	    /* for some blocks j can be past bottom */
X	reduce[j] = 1;
X	for (i = 0; i < BOARDWIDTH && reduce[j]; i++)
X	    reduce[j] &= boardmap[i][j];
X	reducing |= reduce[j];
X	if (reduce[j])	/* save any rows-to-be-reduced for flashing */
X	    pw_read (savepr, 0, (j-y)*BLOCKSIZE, BOARDWIDTH*BLOCKSIZE,
X		BLOCKSIZE, PIX_SRC, pw, BOARD_X, BOARD_Y+j*BLOCKSIZE);
X    }
X    if (!reducing)  return (0);
X    select (1, 0, 0, 0, &delay_50ms);
X    for (i = 0; i < 3; i++)  {	/* flash rows 3 times */
X	for (j = y+3; j >= y; j--)  {
X	    if (j < BOARDHEIGHT && reduce[j])	/* erase rows */
X		pw_writebackground (pw, BOARD_X, BOARD_Y+j*BLOCKSIZE,
X		    BOARDWIDTH*BLOCKSIZE, BLOCKSIZE, PIX_CLR);
X	}
X	select (1, 0, 0, 0, &delay_50ms);
X	for (j = y+3; j >= y; j--)  {
X	    if (j < BOARDHEIGHT && reduce[j])	/* restore rows */
X		pw_rop (pw, BOARD_X, BOARD_Y+j*BLOCKSIZE, BOARDWIDTH*BLOCKSIZE,
X		    BLOCKSIZE, PIX_SRC, savepr, 0, (j-y)*BLOCKSIZE);
X	}
X	select (1, 0, 0, 0, &delay_50ms);
X    }
X    pw_batch_on (pw);
X    /*  next, starting from the bottom of the board,
X	we do nothing if the row is to be deleted,
X	we copy the non-full row down by how many have been deleted
X	under it */
X    for (j = y+3; j >= 0; j--)  {	/* remove rows */
X	if (j >= BOARDHEIGHT)  continue;
X	if (reduce[j])  {
X	    skip++;
X	    reduce[j] = 0;
X	}
X	else if (skip > 0)  {
X	    for (i = 0; i < BOARDWIDTH; i++)
X		boardmap[i][j+skip] = boardmap[i][j];
X	    pw_copy (pw, BOARD_X, BOARD_Y+(j+skip)*BLOCKSIZE,
X		BLOCKSIZE*BOARDWIDTH, BLOCKSIZE,		/* one row */
X		PIX_SRC, pw, BOARD_X, BOARD_Y+j*BLOCKSIZE);
X	}
X    }
X    /* shift remaining blocks down by number of deleted rows */
X    pw_writebackground (pw, BOARD_X, BOARD_Y, BLOCKSIZE*BOARDWIDTH,
X	BLOCKSIZE*skip, PIX_CLR);
X    pw_batch_off (pw);
X    return (skip);
X}
X
X#define BORDER_PIXOP (PIX_SRC | PIX_COLOR(RED))
X#define TEXT_PIXOP (PIX_SRC | PIX_COLOR(YELLOW))
X
X/* close_board does the closing door effect when the game is over */
Xvoid
Xclose_board ()
X{
X    int i, j;
X    static struct timeval delay_100ms = { 0, 100000 };
X
X    for (i = 0; i < BOARDHEIGHT; i++)		/* clear boardmap */
X	for (j = 0; j < BOARDWIDTH; j++)  boardmap[j][i] = 0;
X    select (1, 0, 0, 0, &delay_100ms);
X    for (i = 0; i < BOARDHEIGHT/2; i++)  {
X	pw_batch_on (pw);
X	for (j = 0; j < BOARDWIDTH; j++)  {
X	    draw_block (BOARD_X+j*BLOCKSIZE, BOARD_Y+i*BLOCKSIZE, 2)
X	    draw_block (BOARD_X+j*BLOCKSIZE,
X		BOARD_Y+(BOARDHEIGHT-1-i)*BLOCKSIZE, 2);
X	}
X	pw_batch_off (pw);
X	select (1, 0, 0, 0, &delay_100ms);
X    }
X    pw_text (pw, BOARD_X+2*BLOCKSIZE, BOARD_Y+BLOCKSIZE*BOARDHEIGHT/2,
X	TEXT_PIXOP, bigfont, "GAME OVER");
X    select (1, 0, 0, 0, &delay_100ms);
X}
X
X
Xvoid draw_score (lines, score, level)
Xint lines, score, level;
X{
X    char s[10];
X
X    pw_batch_on (pw);
X    sprintf (s, "%6d", lines);
X    pw_text (pw, 100, LINES_Y, TEXT_PIXOP, bigfont, s);
X    sprintf (s, "%6d", score);
X    pw_text (pw, 100, SCORE_Y, TEXT_PIXOP, bigfont, s);
X    sprintf (s, "%6d", level);
X    pw_text (pw, 100, LEVEL_Y, TEXT_PIXOP, bigfont, s);
X    pw_batch_off (pw);
X}
X
X
Xvoid
Xdraw_board ()
X{
X    pw_batch_on (pw);
X    pw_writebackground (pw, 0, 0, pw->pw_pixrect->pr_width,
X	pw->pw_pixrect->pr_height, PIX_CLR);	/* clear screen */
X    pw_writebackground (pw, BOARD_X-4, BOARD_Y-4, 2, BOARDHEIGHT*BLOCKSIZE+8,
X	BORDER_PIXOP);
X    pw_writebackground (pw, BOARD_X-4, BOARD_Y-4, BOARDWIDTH*BLOCKSIZE+8, 2,
X	BORDER_PIXOP);
X    pw_writebackground (pw, BOARD_X+BOARDWIDTH*BLOCKSIZE+2, BOARD_Y-4,
X	2, BOARDHEIGHT*BLOCKSIZE+8, BORDER_PIXOP);
X    pw_writebackground (pw, BOARD_X-4, BOARD_Y+BOARDHEIGHT*BLOCKSIZE+2,
X	BOARDWIDTH*BLOCKSIZE+8, 2, BORDER_PIXOP);
X    pw_ttext (pw, 20, SCORE_Y, TEXT_PIXOP, bigfont, "SCORE");
X    pw_ttext (pw, 20, LINES_Y, TEXT_PIXOP, bigfont, "LINES");
X    pw_ttext (pw, 20, LEVEL_Y, TEXT_PIXOP, bigfont, "LEVEL");
X    pw_batch_off (pw);
X}
X
X
X/* init_pw gets the pixwin from the canvas and sets up the colormap */
Xvoid
Xinit_pw (forcebw)
Xint forcebw;
X{
X    u_char red[TETRISCMSSIZE], green[TETRISCMSSIZE], blue[TETRISCMSSIZE];
X
X    bigfont = pf_open ("/usr/lib/fonts/fixedwidthfonts/gallant.r.19");
X    pw = (Pixwin *) window_get (canvas, WIN_PIXWIN);
X    incolor = (pw->pw_pixrect->pr_depth == 8);
X    if (forcebw)  incolor = 0;
X    tetris_cms(red, green, blue)
X    pw_setcmsname (pw, "suntetris");
X    pw_putcolormap (pw, 0, TETRISCMSSIZE, red, green, blue);
X    pw = canvas_pixwin (canvas);
X    pw_setcmsname (pw, "suntetris");
X    pw_putcolormap (pw, 0, TETRISCMSSIZE, red, green, blue);
X    savepr = mem_create (BOARDWIDTH*BLOCKSIZE, 4*BLOCKSIZE,
X		 incolor?8:1);
X}
X
X
X/* rand_blocks draws a random assortment of blocks to the specified height
X   on the board and logs them into the boardmap */
Xvoid
Xrand_blocks (height)
Xint height;
X{
X    int x, y, r;
X
X    pw_batch_on (pw);
X    for (y = BOARDHEIGHT-height; y < BOARDHEIGHT; y++)  {
X	for (x = 0; x < BOARDWIDTH; x ++)  {
X	    r = random ();
X	    if (r % 4 == 0)  {
X		boardmap[x][y] = 1;
X		draw_block (BOARD_X+x*BLOCKSIZE,
X		    BOARD_Y+y*BLOCKSIZE, (r/4) % 7 + 1)
X	    }
X	}
X    }
X    pw_batch_off (pw);
X}
X
X
X#define BOXSIZE 32
X#define CHOICE_PIXOP PIX_NOT(PIX_SRC)
X#define CADJX 10
X#define CADJY BOXSIZE-8
X#define LVX 50
X#define HTX 260
X#define LVY BOARD_Y+10
X#define HTY BOARD_Y+10
X
X/* display_choices draws the level selection and height selection boxes */
Xvoid
Xdisplay_choices ()
X{
X    int i;
X
X    pw_batch_on (pw);
X    pw_writebackground (pw, 0, 0, pw->pw_pixrect->pr_width,
X	pw->pw_pixrect->pr_height, PIX_CLR);	/* clear screen */
X    pw_text (pw, LVX, BOARD_Y, PIX_SRC, bigfont, "LEVEL");
X    pw_text (pw, HTX, BOARD_Y, PIX_SRC, bigfont, "HEIGHT");
X    for (i = 0; i < 6; i++)
X	pw_writebackground (pw, LVX+i*BOXSIZE, LVY, 2, 2*BOXSIZE, PIX_SET);
X    for (i = 0; i < 4; i++)
X	pw_writebackground (pw, HTX+i*BOXSIZE, HTY, 2, 2*BOXSIZE, PIX_SET);
X    for (i = 0; i < 3; i++)  {
X	pw_writebackground (pw, LVX, LVY+i*BOXSIZE, 5*BOXSIZE+2, 2,
X	    PIX_SET);
X	pw_writebackground (pw, HTX, HTY+i*BOXSIZE, 3*BOXSIZE+2, 2,
X	    PIX_SET);
X    }
X    for (i = 0; i <= 9; i++)
X	pw_char (pw, LVX+(i%5)*32+CADJX, LVY+(i/5)*32+CADJY, PIX_SRC,
X	    bigfont, i+'0');
X    pw_char (pw, HTX+CADJX, HTY+CADJY, PIX_SRC, bigfont, '0');
X    pw_char (pw, HTX+BOXSIZE+CADJX, HTY+CADJY, PIX_SRC, bigfont, '4');
X    pw_char (pw, HTX+2*BOXSIZE+CADJX, HTY+CADJY, PIX_SRC, bigfont, '7');
X    pw_text (pw, HTX-6+CADJX, HTY+BOXSIZE+CADJY, PIX_SRC, bigfont, "10");
X    pw_text (pw, HTX-6+BOXSIZE+CADJX, HTY+BOXSIZE+CADJY, PIX_SRC, bigfont,
X	"13");
X    pw_text (pw, HTX-6+2*BOXSIZE+CADJX, HTY+BOXSIZE+CADJY, PIX_SRC, bigfont,
X	">>");
X    pw_batch_off (pw);
X}
X
X
X/* select_level inverts the box corresponding to the specified level */
Xvoid
Xselect_level (level)
Xint level;
X{
X    pw_copy (pw, LVX+(level%5)*BOXSIZE+2, LVY+(level/5)*BOXSIZE+2,
X	BOXSIZE-2, BOXSIZE-2, PIX_NOT(PIX_SRC),
X	pw, LVX+(level%5)*BOXSIZE+2, LVY+(level/5)*BOXSIZE+2);
X}
X
X
X/* select_height inverts the box corresponding to the specified height
X   position onscreen (0-5) not the actual height (0,4,7,10,13,>>) */
Xvoid
Xselect_height (height)
Xint height;
X{
X    pw_copy (pw, HTX+(height%3)*BOXSIZE+2, HTY+(height/3)*BOXSIZE+2,
X	BOXSIZE-2, BOXSIZE-2, PIX_NOT(PIX_SRC),
X	pw, HTX+(height%3)*BOXSIZE+2, HTY+(height/3)*BOXSIZE+2);
X}
X
X
Xstatic struct highscores  {
X    char name[16];
X    int level, score;
X} highs[10] =  {
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X    "nobody", 0, 0,
X};
X
X#define SPACING 32
X#define HIGHS_X 30
X#define HIGHS_Y 80
X
Xvoid
Xdisplay_hs ()
X{
X    int i;
X    char s[8];
X
X    pw_batch_on (pw);
X    pw_writebackground (pw, 0, 0, pw->pw_pixrect->pr_width,
X	pw->pw_pixrect->pr_height, PIX_CLR);	/* clear screen */
X    pw_text (pw, HIGHS_X, HIGHS_Y-SPACING, PIX_SRC, bigfont, "NAME");
X    pw_text (pw, HIGHS_X+160, HIGHS_Y-SPACING, PIX_SRC, bigfont, "LEVEL");
X    pw_text (pw, HIGHS_X+270, HIGHS_Y-SPACING, PIX_SRC, bigfont, "SCORE");
X    for (i = 0; i < 10; i++)  {
X	pw_text (pw, HIGHS_X, HIGHS_Y+i*SPACING, PIX_SRC, bigfont,
X	    highs[i].name);
X	pw_char (pw, HIGHS_X+180, HIGHS_Y+i*SPACING, PIX_SRC, bigfont,
X	    highs[i].level+'0');
X	sprintf (s, "%5d", highs[i].score);
X	pw_text (pw, HIGHS_X+270, HIGHS_Y+i*SPACING, PIX_SRC, bigfont, s);
X    }
X    pw_batch_off (pw);
X}
X
X
X#ifndef HIGHSCOREFILE
X#define HIGHSCOREFILE suntetris.hs
X#endif HIGHSCOREFILE
X
X/* The file locking here isn't foolproof */
X/* We have an unsecured highscore file */
Xvoid
Xupdate_hs (score, level)
Xint score, level;
X{
X    FILE *fp;
X    int i, j;
X    struct passwd *passwd = getpwuid (getuid ());
X
X    if ((fp = fopen (HIGHSCOREFILE, "r")) != NULL)  {	/* read old scores */
X	lockf (fileno (fp), F_LOCK, 0);
X	while (i < 10 && (fscanf(fp, "%s %d %d", highs[i].name,
X			  &highs[i].level, &highs[i].score) != EOF))  i++;
X	fclose (fp);
X    }
X    for (i = 10; i > 0 && score > highs[i-1].score; i--) ;
X    if (i > 9)  return;
X    if ((fp = fopen (HIGHSCOREFILE, "w")) == NULL)  return;
X    lockf (fileno (fp), F_LOCK, 0);
X    for (j = 9; j > i; j--)  {
X	strcpy (highs[j].name, highs[j-1].name);
X	highs[j].level = highs[j-1].level;
X	highs[j].score = highs[j-1].score;
X    }
X    strcpy (highs[i].name, passwd->pw_name);
X    highs[i].level = level;
X    highs[i].score = score;
X    for (i = 0; i < 10; i++)
X	fprintf (fp, "%s %d %d\n", highs[i].name, highs[i].level,
X		 highs[i].score);
X    fclose (fp);
X}
END_OF_FILE
if test 15955 -ne `wc -c <'suntetris_pw.c'`; then
    echo shar: \"'suntetris_pw.c'\" unpacked with wrong size!
fi
# end of 'suntetris_pw.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    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