[comp.sources.games] v03i080: qix - video game for Suns, Part01/02

games@tekred.TEK.COM (01/29/88)

Submitted by: Dan Heller <island!argv@sun.com>
Comp.sources.games: Volume 3, Issue 80
Archive-name: qix/Part01

	[I compiled and ran this with no problem on my Sun 3/60.  -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 joystick.c main.c regions.c score.c
#   sparks.c
# Wrapped by billr@saab on Tue Jan 26 18:06:30 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(772 characters\)
sed "s/^X//" >README <<'END_OF_README'
XThe game of Qix for the Sun3 workstation running Sunview (probably 3.0)--
XAppearance ONLY shamelessly stolen from the real video game wonderfully
Xand admirably written by individual(s) unknown at Taito Corp (I think).
X
XMove mouse to go in direction.  Left button does fast draw. Middle does
Xslow draw.  Rogue/vi keys moves -- upper case draws.  There is no slow
Xdraw for keyboard input.
X
XThere is not yet a stage where you split two qix.
X
XSparx don't do what they should; they move randomly and without purpose.
XThey only kill the user -- there are no aggressive sparx.
X
XThe qix will sometimes get into an infinite loop trying to get itself
Xor a portion of itself out of a place it shouldn't be (closed area).
X
X	-Dan Heller (island!argv@sun.com or argv@spam.istc.sri.com)
END_OF_README
if test 772 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(864 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                  1	This shipping list
X Makefile                  2	
X README                    1	
X joystick.c                1	
X joystick.dn               2	
X joystick.lf               2	
X joystick.rt               2	
X joystick.stop             2	
X joystick.up               2	
X main.c                    1	
X marker.cursor             2	
X mouse.rt.icon             2	
X polyfill.c                2	
X polyfill_rec.c            2	
X polygon_area.c            2	
X qix.h                     2	
X qix.icon                  2	
X qmove.c                   2	
X regions.c                 1	
X score.c                   1	
X spark1.pr                 2	
X spark2.pr                 2	
X spark3.pr                 2	
X spark4.pr                 2	
X sparks.c                  1	
END_OF_MANIFEST
if test 864 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f joystick.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"joystick.c\"
else
echo shar: Extracting \"joystick.c\" \(16953 characters\)
sed "s/^X//" >joystick.c <<'END_OF_joystick.c'
X#include "qix.h"
X#include "math.h"
X
X/* the pen marker */
Xshort marker_curs_dat[] = {
X#include "marker.cursor"
X};
Xmpr_static(pen_image,          16, 16, 1, marker_curs_dat);
X
Xshort fast_draw_off_dat[] = {
X#include <images/mouse_left_hand.pr>
X};
Xmpr_static(ms_fast_off,      16, 23, 1, fast_draw_off_dat);
X
Xshort fast_draw_on_dat[] = {
X#include <images/mouse_left_hand_grey.pr>
X};
Xmpr_static(ms_fast_on,     16, 23, 1, fast_draw_on_dat);
X
Xshort slow_draw_off_dat[] = {
X#include <images/mouse_mid_hand.pr>
X};
Xmpr_static(ms_slow_off,      16, 23, 1, slow_draw_off_dat);
X
Xshort slow_draw_on_dat[] = {
X#include <images/mouse_mid_hand_grey.pr>
X};
Xmpr_static(ms_slow_on,     16, 23, 1, slow_draw_on_dat);
X
X/* joystick (really, arrow) symbols */
Xshort left_arrow_dat[] = {
X#include "joystick.lf"
X};
Xmpr_static(joystick_left,   64, 64, 1, left_arrow_dat);
X
Xshort right_arrow_dat[] = {
X#include "joystick.rt"
X};
Xmpr_static(joystick_right,  64, 64, 1, right_arrow_dat);
X
Xshort up_arrow_dat[] = {
X#include "joystick.up"
X};
Xmpr_static(joystick_up,     64, 64, 1, up_arrow_dat);
X
Xshort dn_arrow_dat[] = {
X#include "joystick.dn"
X};
Xmpr_static(joystick_down,   64, 64, 1, dn_arrow_dat);
X
X/* a circle with line thru it */
Xshort stop_dat[] = {
X#include "joystick.stop"
X};
Xmpr_static(joystick_stop,   64, 64, 1, stop_dat);
X
X/* a big right mouse button */
Xshort ready_icon_dat[] = {
X#include "mouse.rt.icon"
X};
Xmpr_static(ready_icon,      64, 64, 1, ready_icon_dat);
X
X/*
X * the main window selection catches input interrupts and calls this
X * routine to process what just happened.  Nothing is actually done
X * besides that -- that is, the pen is not moved, the qix isn't moved,
X * and sparks don't move.  however, we will reset the "moving" variable,
X * start the or finish the "drawing" state, and reset the icon that displays
X * the joystick icon that indicates which way the user is moving.
X */
Xmove_joystick(canvas, event, data)
Xregister Canvas canvas;
Xregister Event *event;
X{
X    register int ID = event->ie_code;
X    static start_fast;
X
X    if (play_mode != REAL_PLAY && ID != ' ' && ID != MS_RIGHT)
X	return;
X
X    if ((ID == LOC_MOVE) && moving != NO_MOVE) {
X	register int delta_x, delta_y;
X	if (event_x(event) <= 0)
X	    event_set_x(event, 1);
X	if (event_y(event) <= 0)
X	    event_set_y(event, 1);
X	delta_x = event_x(event) - MID_X;
X	delta_y = event_y(event) - MID_Y;
X
X	/* didn't move enough */
X	if (abs(delta_x) <= SENS_FACTOR && abs(delta_y) <= SENS_FACTOR)
X	    return;
X
X	if (abs(delta_x) > abs(delta_y))
X	    if (delta_x > 0)
X		moving = RIGHT;
X	    else
X		moving = LEFT;
X	else
X	    if (delta_y > 0)
X		moving = DOWN;
X	    else
X		moving = UP;
X    }
X
X    if (isascii(ID) && ID != ' ') {
X#ifdef DEBUG
X	if (isdigit(ID)) {
X	    debug = ID - '0';
X	    msg("Debugging level set to %d", debug);
X	    sleep(2);
X	    remove_msgs();
X	    return;
X	} else
X#endif DEBUG
X	if (event_is_up(event)) {
X	    /* up events -- user released a key, so stop moving */
X	    /* unimplemented -- holding key down results in fast up/down's */
X	    moving = STOP;
X	    drawing = 0;
X	    return;
X	} else if (event_shift_is_down(event))
X	    fast = drawing = 1;
X	else if (event_meta_is_down(event))
X	    fast = !(drawing = 1);
X	else
X	    drawing = 0;
X    }
X
X    switch(ID) {
X	when MS_LEFT :
X	    fast = (drawing = (!event_is_up(event)));
X	    start_fast = TRUE;
X	    return;
X	when MS_MIDDLE :
X	    fast = 0;
X	    if (start_fast == TRUE && region)
X		drawing = 0;
X	    else
X		drawing = !event_is_up(event);
X	    return;
X	when MS_RIGHT : case ' ' :
X	    if (event_is_up(event))
X		break;
X	    /* if moving == NO_MOVE, RIGHT, LEFT, UP or DOWN */
X	    if (!is_alive || play_mode != REAL_PLAY) {
X		lives = 0;
X		play_mode = REAL_PLAY;  /* set Nowhere else but here! */
X		change_life(LIVE); /* "next" life in current game */
X	    } else if (moving != STOP) {
X		/* NO_MOVE state goes right to STOP state */
X		if (moving == NO_MOVE)
X		    reset_joystick_win(FALSE);
X		/* all other directions go right to STOP state */
X		moving = STOP;
X	    } else
X		/* STOP state goes right to NO_MOVE state */
X		moving = NO_MOVE, reset_joystick_win(TRUE);
X	when 'h' : case 'H' : case KEY_RIGHT(10) :
X	    moving = LEFT;
X	when 'l' : case 'L' : case KEY_RIGHT(12) :
X	    moving = RIGHT;
X	when 'j' : case 'J' : case KEY_RIGHT(14) :
X	    moving = DOWN;
X	when 'k' : case 'K' : case KEY_RIGHT(8) :
X	    moving = UP;
X	when LOC_MOVE : break; /* let those thru! */
X#ifdef DEBUG
X	case '@' : no_qix_kill = !no_qix_kill; drawing = 0;
X	when '#' : clear_sparks();
X	when '+' : lives = min(lives+1, MAX_LIVES); update_score(); drawing = 0;
X	when '-' : lives = max(lives-1, 1); update_score(); drawing = 0;
X	when '!' : drawing = 0;
X	    if (play_mode == REAL_PLAY) {
X		lives = 0;
X		change_life(LIVE);
X	    } /* fall thru */
X#endif DEBUG
X	default :
X	    return; /* do nothing */
X    }
X    if (moving != NO_MOVE &&
X	(event_x(event) != MID_X || event_y(event) != MID_Y))
X	window_set(canvas, WIN_MOUSE_XY, MID_X, MID_Y, 0);
X}
X
X/*
X * The main routine waits for input from the user until an alarm goes off
X * which says, "ok, go to the next state of the machine" which may very
X * well be "do nothing".  The timer is restarted when we're done processing
X * whatever we have to process.  This is where the pen actually moves to the
X * next position, drawing lines, or running scared from a vicious spark.
X */
Xmove_pen()
X{
X    register int x = pen_x, y = pen_y, new_value, old_value;
X    static slow_draw;
X
X    if (!is_alive && lives > 0) {
X	/* user has died and is waiting to start again */
X	sleep(2);
X	change_life(LIVE);
X	stop_timer(); /* change_life restarts it */
X	msg("Ready?");
X	sleep(2);
X	remove_msgs(0);
X	start_timer();
X	return;
X    }
X    /* don't play if the joystick isn't active */
X    if (moving == NO_MOVE || play_mode != REAL_PLAY) {
X	if (play_mode != REAL_PLAY) {
X	    time_left--;
X	    if (play_mode == DEMO && lives > 0) {
X		if (time_left == 0) {
X		    int lastmove = moving;
X		    register int left, right, up, down;
X		    drawing = 1;
X		    if (!(board[x][y] & NEW_LINE))
X			fast = (rrand() & 3);
X		    left = (!check_painted(x, y, CL_PNT_LEFT) &&
X			    !(board[x-1][y] & NEW_LINE));
X
X		    right = (!check_painted(x, y, CL_PNT_RIGHT) &&
X			     !(board[x+1][y] & NEW_LINE));
X
X		    up = (!check_painted(x, y, CL_PNT_TOP) &&
X			  !(board[x][y-1] & NEW_LINE));
X
X		    down = (!check_painted(x, y, CL_PNT_BOT) &&
X			    !(board[x][y+1] & NEW_LINE));
X
X		    if (!left && !right && !up && !down)
X			moving = STOP, time_left = -1; /* let fuse catch up */
X		    else {
X			int dx = region ? region->x - x : 0;
X			int dy = region ? region->y - y : 0;
X			time_left = 15 + (rrand() & 31);
X			/* first attempt to limit box to less than 25 X 25 */
X			if (region && (_ABS(dx) > 25 || _ABS(dy) > 25)) {
X			    if (_ABS(dx) > 25 ||
X				_ABS(dy) > 25 && (moving == LEFT ||
X						  moving == RIGHT))
X				if (moving != LEFT && moving != RIGHT)
X				    moving = (dx > 25) ? RIGHT : LEFT;
X				else
X				    moving = (dy > 0) ? DOWN : UP;
X			    else if (_ABS(dy) > 25)
X				if (moving != UP && moving != DOWN)
X				    moving = (dy > 25) ? DOWN : UP;
X				else
X				    moving = (dx > 0) ? RIGHT : LEFT;
X			}
X			/* Make sure we can move in that direction */
X			while (moving == lastmove ||
X			    !left && moving == LEFT || !up && moving == UP ||
X			    !down && moving == DOWN || !right && moving== RIGHT)
X			    moving = LEFT + (rrand() & 3);
X		    }
X		}
X	    } else if (time_left <= 0) {
X		drawing = 0;
X		level = -2;
X		moving = NO_MOVE;
X		init_qix();
X		switch (play_mode = (play_mode + 1) % (DEMO+1)) {
X		    when SHOW_SCORES :
X			clear_board();
X			score_board(TRUE, FALSE);
X			time_left = 50;
X		    when SHOW_POINTS :
X			score = 0;
X			update_score();
X			move_fuse(fuse = NULL); /* just in case */
X			rm_cur_line(PIX_CLR);
X			clear_board();
X			place_pen();
X			msg("Direct the mouse to control joystick.");
X			time_left = 315;
X			moving = LEFT;
X		    when SHOW_QIX :
X			remove_msgs(0);
X			msg("Your Enemies:");
X			sleep(2);
X			time_left = 40;
X		    when SHOW_SPARKS :
X			time_left = 90;
X		    when SHOW_FUSE :
X			drawing = fast = 1;
X			moving = UP;
X			time_left = 280;
X		    when SHOW_SPIRAL :
X			moving = STOP;
X			drawing = 0;
X			time_left = 100;
X		    when DEMO :
X			time_left = 1;
X			change_life(LIVE);
X			stop_timer();
X	    msg("Enclose more than\n75%%\nof the play area for extra bonus.");
X			sleep(2);
X			remove_msgs(0);
X			level = -2;
X			drawing = fast = 1;
X			goto done;
X		}
X	    } else switch (play_mode) {
X		when SHOW_QIX :
X		    move_qix();
X		    if (time_left == 1) {
X			pw_text(draw_win, 200,200,PIX_SRC,big_font, "The qix.");
X			sleep(2);
X		    }
X		when SHOW_SPARKS :
X		    move_sparks();
X		    if (time_left == 1) {
X			pw_text(draw_win, 15, 110, PIX_SRC, big_font, "Sparx.");
X			pw_text(draw_win,625, 110, PIX_SRC, big_font, "Sparx.");
X			sleep(2);
X		    }
X		when SHOW_FUSE :
X		    /* after the pw_text, this moves into spiral death trap */
X		    switch (time_left) {
X			when 230 :
X			    drawing = 0;
X			    pw_text(draw_win,
X				convert_x(pen_x - 7), convert_y(pen_y + 7),
X				PIX_SRC, big_font, "The fuse.");
X			when 80 :
X			    pw_text(draw_win, 265, 445,
X				PIX_SRC, big_font, "The Spiral Death Trap.");
X			case 200 : case 240 : case 40 : case 20 :
X			    moving = LEFT, drawing = 1;
X			when 110 : case  55 : case 30 : moving = RIGHT;
X			when 126 : case  65 : case 35 : moving = UP;
X			when  95 : case  45 : case 25 : moving = DOWN;
X		    }
X		    goto movit;
X		when SHOW_SPIRAL :
X		    if (fuse) { /* when we die, fuse will be NULL */
X			time_left = 2;
X			goto movit;
X		    } else if (region) {
X			move_fuse(fuse = NULL);
X			rm_cur_line(PIX_SRC);
X		    }
X		when SHOW_POINTS : {
X		    char buf[5];
X		    switch (time_left) {
X			when 270 :
X			    msg("Use LEFT mouse button for Fast Draw.");
X			    drawing = fast = 1, moving = UP;
X			    score = 0;
X			when 170 :
X			    msg("Use MIDDLE mouse button for Slow Draw.");
X			    drawing = 1, fast = 0, moving = UP;
X			    score = 0;
X			when 250 : case 130 : moving = RIGHT;
X			when 230 : case  90 : moving = DOWN;
X			when 210 : drawing = 0, moving = RIGHT;
X			    pw_text(draw_win,
X				convert_x(pen_x - 12), convert_y(pen_y - 25),
X				PIX_SRC, big_font, sprintf(buf, "%d", score));
X			when 49 : /* make sure region is closed */
X			    msg("Use RIGHT mouse button to STOP movement.");
X			    pw_text(draw_win,
X				convert_x(pen_x - 12), convert_y(pen_y - 25),
X				PIX_SRC, big_font, sprintf(buf, "%d", score));
X			when 15 : drawing = 0, moving = RIGHT;
X		    }
X		    goto movit; /* avoid moving qix and sparks */
X		}
X	    }
X	}
X	if (play_mode != DEMO)
X	    goto done;
X    }
X
X    if (move_qix() == -1) {
X	change_life(DIE);
X	return;
X    }
X
X    if (move_sparks() == -1) /* player got hosed */
X	return; /* don't restart timer */
X
Xmovit:
X    draw_joystick();
X    if (moving == STOP) {
X	if (!cur_coord || move_fuse(&fuse) != -1)  /* -1: fuse caught up */
X	    start_timer();
X	return;
X    }
X    /* this forces the last fuse to go away */
X    (void) move_fuse((struct region *)NULL); /* this can't return -1 */
X    if (drawing && !fast && board[pen_x][pen_y] & NEW_LINE
X	&& (slow_draw = !slow_draw))
X	goto done;
X
X    /*
X     * x,y will be the new (proposed) position if the following is true...
X     * if not drawing, then check to see if the current cell we're at connects
X     * with the proposed new position.  Logic says that it will connect if
X     * it "points" that way.. f'rinstance, you can't move left if the current
X     * cell doesn't have the "cell-line-left" (CL_LN_LF) attribute. Also,
X     * check to see if the current cell has the NEW_LINE attribute. If so,
X     * user should be drawing. If he isn't, the fuse starts.
X     */
X    switch (moving) {
X	when LEFT :
X	    if (check_painted(x, y, CL_PNT_LEFT) ||
X		    !drawing && !(board[x][y] & (CL_LN_LF|NEW_LINE))) {
X		if (play_mode == DEMO)
X		    time_left = 1;
X		goto done;
X	    }
X	    x--;
X	when RIGHT :
X	    if (check_painted(x, y, CL_PNT_RIGHT) ||
X		    !drawing && !(board[x][y] & (CL_LN_RT|NEW_LINE))) {
X		if (play_mode == DEMO)
X		    time_left = 1;
X		goto done;
X	    }
X	    x++;
X	when UP :
X	    if (check_painted(x, y, CL_PNT_TOP) ||
X		    !drawing && !(board[x][y] & (CL_LN_UP|NEW_LINE))) {
X		if (play_mode == DEMO)
X		    time_left = 1;
X		goto done;
X	    }
X	    --y;
X	when DOWN :
X	    if (check_painted(x, y, CL_PNT_BOT) ||
X		    !drawing && !(board[x][y] & (CL_LN_DN|NEW_LINE))) {
X		if (play_mode == DEMO)
X		    time_left = 1;
X		goto done;
X	    }
X	    ++y;
X    }
X    old_value = board[pen_x][pen_y];
X    new_value = board[x][y];
X    /*
X     * If drawing, you can't move onto yourself (a "new" line). [start fuse]
X     * You can alwasy move onto an old line (completing a region if drawing).
X     * If not drawing, you must be on an old line and moving
X     * onto another old line. If we're not drawing and *should* be drawing
X     * (determined by old_value's NEW_LINE bit set), start a fuse.
X     * Also, player can't cheat by fast drawing and suddenly changing to
X     * a slow draw just to close a region. Test to see if start_fast is
X     * set correctly by testing "region" first.
X     */
X    if (drawing && (new_value & NEW_LINE) && !(new_value & OLD_LINE) ||
X	!drawing && (old_value & NEW_LINE)) {
X	if (!fuse) /* if a fuse isn't going, ignite one */
X	    fuse = region;
X	if (play_mode == DEMO)
X	    time_left = 1;
X	else
X	    moving = STOP;
X	goto done;
X    }
X
X    /* erase the pen_image, move, reset pen_image, draw line */
X    place_pen();
X
X    /* next, determine that if we are drawing, ignore that fact if we
X     * are attempting to draw on top of an already drawn line.  If we
X     * are creating a new line, then go ahead and create it.
X     */
X    if (drawing) {
X	switch (moving) {
X	    when LEFT :
X		if (board[pen_x][pen_y] & CL_LN_LF)
X		    goto redraw_pen;
X		board[pen_x][pen_y] |= CL_LN_LF;
X		board[x][y] |= CL_LN_RT;
X	    when RIGHT :
X		if (board[pen_x][pen_y] & CL_LN_RT)
X		    goto redraw_pen;
X		board[pen_x][pen_y] |= CL_LN_RT;
X		board[x][y] |= CL_LN_LF;
X	    when UP :
X		if (board[pen_x][pen_y] & CL_LN_UP)
X		    goto redraw_pen;
X		board[pen_x][pen_y] |= CL_LN_UP;
X		board[x][y] |= CL_LN_DN;
X	    when DOWN :
X		if (board[pen_x][pen_y] & CL_LN_DN)
X		    goto redraw_pen;
X		board[pen_x][pen_y] |= CL_LN_DN;
X		board[x][y] |= CL_LN_UP;
X	}
X	draw(convert_x(x), convert_y(y),
X	     convert_x(pen_x), convert_y(pen_y), PIX_SRC);
X	if (!region) {
X	    saved_edge = old_value;
X	    add_to_line(pen_x, pen_y);
X	    old_value = (board[pen_x][pen_y] |= NEW_LINE);
X	}
X	/* if drawing from a newline onto an old line, a region is completed */
X	if ((old_value & NEW_LINE) && (new_value & OLD_LINE)) {
X	    int new_level = close_region(x, y);
X	    if (!new_level)
X		update_score();
X	    if (new_level || (int)(((double)area_closed/TOTAL_AREA)*100) >= 75){
X		if (!new_level) {
X		    int percent_closed =
X			(int)(((double)area_closed/TOTAL_AREA) * 100);
X		    msg("Closed %d%% of the board.", percent_closed);
X		    if (percent_closed > 75) {
X			score += (percent_closed - 75) * 1000;
X			update_score();
X			msg("1000 bonus points for each percent over 75%%");
X			msg("BONUS: %d", (percent_closed - 75) * 1000);
X		    }
X		} else
X		    level++;
X		sleep(3);
X		clear_board(); /* removes msgs also */
X		change_life(LIVE);
X		stop_timer();
X		if (level < 0)
X		    level++;
X		if (level == 0) {
X		    msg("Split the 2 qix to advance score multiplier.");
X		    sleep(2);
X		    remove_msgs(0);
X		}
X		start_timer();
X		return;
X	    }
X	} else if (new_value == 0) {
X	    board[x][y] |= NEW_LINE;
X	    add_to_line(x, y);
X	}
X    }
Xredraw_pen:
X    pen_x = x, pen_y = y;
X    place_pen(); /* set the new pen image */
Xdone:
X    start_timer();
X}
X
Xdraw_joystick()
X{
X    Pixrect *image = moving == LEFT? &joystick_left :
X		     moving == RIGHT? &joystick_right :
X		     moving == UP? &joystick_up :
X		     moving == DOWN? &joystick_down :
X		     moving == STOP? &joystick_stop : &ready_icon;
X    pw_rop(joystick_win,
X	BOARD_WIDTH_IN_PIXELS/2-32, 2, 64, 64, PIX_SRC, image, 0,0);
X    pw_rop(joystick_win, 100,32, 16,23, PIX_SRC,
X	(drawing && fast)? &ms_fast_on : &ms_fast_off, 0, 0);
X    pw_rop(joystick_win, 150,32, 16,23, PIX_SRC,
X	(drawing && !fast)? &ms_slow_on : &ms_slow_off, 0, 0);
X}
X
X/*
X * if "see_it" -- then show the mouse cursor and stop moving mouse to middle
X * of window allowing allow player to grab beer. If "see_it" is
X * false, then the user is ready to move around, so make cursor go away,
X * and force all mouse moves to return to the middle of window.
X */
Xreset_joystick_win(see_it)
X{
X    static int oldop;
X
X    Cursor cursor = (Cursor)window_get(Draw, WIN_CURSOR);
X
X    if (!see_it) {   /* we don't want to see the cursor, so get rid of it */
X	/* get the current cursor and make it invisible */
X	oldop = (int)cursor_get(cursor, CURSOR_OP);
X	cursor_set(cursor, CURSOR_OP, PIX_DST, 0);
X	moving = STOP;
X	draw_joystick();
X    } else {
X	/* cursor_set(cursor, CURSOR_OP, oldop, 0); */
X	moving = NO_MOVE;
X	draw_joystick();
X    }
X    window_set(Joystick, WIN_CURSOR, cursor, 0);
X    window_set(Draw, WIN_CURSOR, cursor, 0);
X}
END_OF_joystick.c
if test 16953 -ne `wc -c <joystick.c`; then
    echo shar: \"joystick.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"main.c\"
else
echo shar: Extracting \"main.c\" \(9961 characters\)
sed "s/^X//" >main.c <<'END_OF_main.c'
X/*
X * The game of Qix for the Sun3 workstation running Sunview (probably 3.0)--
X * Appearance ONLY shamelessly stolen from the real video game wonderfully
X * and admirably written by individual(s) unknown at Taito Corp (I think).
X *
X * Copyright 1987 by Dan Heller (island!argv@sun.com or argv@spam.istc.sri.com)
X *
X * Various polygon filling routines written by
X *   -- Dan "Sky" Shultz (island!sky@sun.com)  and
X *   -- Don Hatch (splat%ucscb@ucscc.ucsc.edu [fall, 1987])
X *      additional help (general debugging, recursive polyfill)
X *
X * Move mouse to go in direction.  Left button does fast draw. Middle does
X * slow draw.  Rogue/vi keys moves -- upper case draws.  There is no slow
X * draw for keyboard input.
X *
X * There is not yet a stage where you split two qix.
X *
X * Sparx don't do what they should; they move randomly and without purpose.
X * They only kill the user -- there are no aggressive sparx.
X *
X * The qix will sometimes get into an infinite loop trying to get itself
X * or a portion of itself out of a place it shouldn't be (closed area).
X */
X
X#include "qix.h"
X
X/* the main icon for when the tool is closed */
Xshort qix_icon_dat[] = {
X#include "qix.icon"
X};
XDEFINE_ICON_FROM_IMAGE(qix_icon, qix_icon_dat);
X
Xint (*old_repaint_func)();
X
X
Xredraw(args)
X{
X    stop_timer();
X    (*old_repaint_func)(&args);
X    start_timer();
X}
X
Xmain(argc, argv)
Xchar *argv[];
X{
X    int catch();
X    char **newargv = argv;
X
X    (void) signal(SIGBUS, catch);
X    (void) signal(SIGSEGV, catch);
X    (void) signal(SIGXCPU, catch);
X
X#ifdef DEBUG
X    /*
X     * specify debug levels "-d level"
X     * a level of 2 prints polygon fill info. 4 disables spark-generation
X     * but doesn't kill current sparks.  debug level 1 does prints things...
X     */
X    while (*++newargv)
X	if (!strcmp(*newargv, "-q"))
X	    no_qix_kill = 1;
X	else if (!strcmp(*newargv, "-d"))
X	    debug = (*++newargv) ? atoi(*newargv) : 1;
X#endif DEBUG
X
X    frame = window_create(NULL, FRAME,
X	FRAME_LABEL, argv[0],
X	WIN_X, 250, WIN_Y, 45,
X	FRAME_ICON, &qix_icon,
X	FRAME_ARGS, argc, argv,
X	FRAME_NO_CONFIRM, TRUE,
X	0);
X
X    Draw = window_create(frame, CANVAS,
X	WIN_HEIGHT, BOARD_HEIGHT_IN_PIXELS,
X	WIN_WIDTH,  BOARD_WIDTH_IN_PIXELS,
X	WIN_EVENT_PROC, move_joystick,
X	0);
X
X    draw_win = canvas_pixwin(Draw);
X    window_set(Draw,
X	CANVAS_FAST_MONO, TRUE,
X	WIN_CONSUME_PICK_EVENTS,
X	    WIN_MOUSE_BUTTONS,
X	    0,
X	WIN_CONSUME_KBD_EVENTS,
X	    WIN_ASCII_EVENTS,
X	    SHIFT_CTRL, SHIFT_META,
X	    0,
X	WIN_INPUT_DESIGNEE, window_get(Draw, WIN_DEVICE_NUMBER),
X	0);
X
X    Joystick = window_create(frame, CANVAS,
X	WIN_X, 0,
X	WIN_BELOW, Draw,
X	WIN_HEIGHT, 68,
X	WIN_WIDTH, WIN_EXTEND_TO_EDGE,
X	0);
X    joystick_win = canvas_pixwin(Joystick);
X
X    window_fit(frame);
X
X    if (!(small_font = pf_open("/usr/people/argv/computer.14")) &&
X	!(small_font = pf_default()) ||
X	!(big_font = pf_open("/usr/lib/fonts/fixedwidthfonts/serif.r.16")) &&
X	!(big_font = pf_default()))
X	perror("can't open default font"), exit(1);
X
X    level = -2; /* two screens before player may split two qix */
X    moving = NO_MOVE;
X    fast = 1,
X
X    srandom(time(0));
X    srand(time(0));
X    update_score();
X
X    init_qix();
X    draw_joystick();
X    pw_text(joystick_win, 92, 24, PIX_SRC, small_font, "Fast  Slow");
X    play_mode = SHOW_SCORES;
X    update_score();
X    score_board(TRUE, FALSE);
X    time_left = 100; /* timeout before next demo mode switch */
X    (void) signal(SIGALRM, move_pen);
X    old_repaint_func = (int(*)())window_get(frame, CANVAS_REPAINT_PROC);
X    window_set(frame, CANVAS_REPAINT_PROC, redraw, 0);
X    start_timer();
X
X    window_main_loop(frame);		/* main loop to read input */
X    exit(0);
X}
X
Xclear_board()
X{
X    register int x, y;
X
X    clear_sparks();
X    area_closed = 0;
X
X    pen_x = (BOARD_WIDTH-1)/2, pen_y = BOARD_HEIGHT-1;
X    remove_msgs(1);
X
X    /* give left->right sweeping effect like the real game */
X    for (x = 0; x < BOARD_WIDTH_IN_PIXELS; x++)
X	draw(x, 0, x, BOARD_HEIGHT_IN_PIXELS-1, PIX_CLR);
X
X    box(convert_x(0), convert_y(0),
X	convert_x(BOARD_WIDTH-1), convert_y(BOARD_HEIGHT-1), PIX_SRC);
X
X    /* clear the interior of the board */
X    for (x = 1; x < BOARD_WIDTH-1; x++)
X	for (y = 1; y < BOARD_HEIGHT-1; y++)
X	    board[x][y] = 0;
X
X    for (x = 1; x < BOARD_WIDTH-1; x++) {
X	board[x][0] = CL_LN_LF | CL_LN_RT | OLD_LINE | CL_PNT_TOP;
X	board[x][BOARD_HEIGHT-1] = CL_LN_LF | CL_LN_RT | OLD_LINE | CL_PNT_BOT;
X    }
X
X    for (y = 1; y < BOARD_HEIGHT-1; y++) {
X	board[0][y] = CL_LN_UP | CL_LN_DN | OLD_LINE | CL_PNT_LEFT;
X	board[BOARD_WIDTH-1][y] = CL_LN_UP | CL_LN_DN | OLD_LINE | CL_PNT_RIGHT;
X    }
X    /* set the corners explicitly */
X    board[0][0] = (CL_LN_DN | CL_LN_RT | CL_PNT_TOP | CL_PNT_LEFT | OLD_LINE);
X    board[0][BOARD_HEIGHT-1] =
X	(CL_LN_UP | CL_LN_RT | CL_PNT_BOT | CL_PNT_LEFT | OLD_LINE);
X    board[BOARD_WIDTH-1][0] =
X        (CL_LN_DN | CL_LN_LF | CL_PNT_TOP | CL_PNT_RIGHT | OLD_LINE);
X    board[BOARD_WIDTH-1][BOARD_HEIGHT-1] =
X	(CL_LN_UP | CL_LN_LF | CL_PNT_BOT | CL_PNT_RIGHT | OLD_LINE);
X}
X
X/*
X * change the status of the player.  If he's living, we add special
X * effects and do the cleanup from the last game. setup the right icons
X * and grab all the io on the screen. If he's dead, release the IO
X * from the screen and reset critical values.
X */
Xchange_life(live_or_die)
X{
X    register int x, n, m = (live_or_die == -1)? 40 : 300;
X
X    stop_timer();
X    if (live_or_die == LIVE) {
X	move_fuse(fuse = (struct region *)NULL); /* erase the last fuse */
X	if (region) {
X	    pen_x = region->x, pen_y = region->y;
X	    rm_cur_line(PIX_CLR); /* remove the current line drawn */
X	}
X	if (lives <= 0) {
X	    if (play_mode == DEMO)
X		lives =  1;
X	    else
X		lives = MAX_LIVES;
X	    clear_board(); /* resets pen_x, pen_y */
X	    level = -2, score = 0;
X	} else {
X	    extern int qix1_x0[], qix1_x1[], qix1_y0[], qix1_y1[];
X	    extern int qix2_x0[], qix2_x1[], qix2_y0[], qix2_y1[];
X
X	    draw(convert_x(qix1_x0[0]), convert_y(qix1_y0[0]),
X		 convert_x(qix1_x1[0]), convert_y(qix1_y1[0]), PIX_CLR);
X	    if (level >= 0)
X		draw(convert_x(qix2_x0[0]), convert_y(qix2_y0[0]),
X		     convert_x(qix2_x1[0]), convert_y(qix2_y1[0]), PIX_CLR);
X	}
X	Speed = 3 + min(level/3, 3);
X#ifdef DEBUG
X	if (debug)
X	    printf("Speed = %d\n", Speed);
X#endif DEBUG
X	clear_sparks();
X	update_score();
X	moving = STOP;
X	drawing = FALSE;
X	if (level > 0) {
X	    msg("All scores now\n%d times\ntheir original value.", level+1);
X	    sleep(3);
X	    remove_msgs(0);
X	}
X	place_pen(); /* make pen appear */
X    }
X
X    for (x = 0; x < 2; x++)
X	for (n = m; n >= 40 && n <= 300; n -= 5 * live_or_die)
X	    box(pen_coord_x(pen_x)-n/2, pen_coord_y(pen_y)-n/2,
X		pen_coord_x(pen_x)+n/2, pen_coord_y(pen_y)+n/2, XOR);
X
X    if (live_or_die == DIE) {
X	is_alive = FALSE;
X	if (--lives <= 0) {
X	    reset_joystick_win(TRUE);
X	    msg("Game Over.");
X	    sleep(2);
X	    /* if he got on the scoreboard, let him put his initials up */
X	    if (play_mode == REAL_PLAY)
X		score_board(FALSE, FALSE);
X	    if (play_mode == SHOW_SPIRAL)
X		time_left = 50; /* demo mode comes after spiral death trap */
X	    else {
X		score_board(TRUE, FALSE);
X		play_mode = SHOW_SCORES;
X		time_left = 100; /* show scores after demo mode or real play */
X	    }
X	    moving = NO_MOVE;
X	} else {
X	    moving = STOP;
X	    drawing = 0;
X	}
X	place_pen(); /* erase pen */
X    } else {
X	is_alive = TRUE;
X	reset_joystick_win(FALSE);
X    }
X    start_timer();
X}
X
Xupdate_score()
X{
X    char buf[128];
X    int x;
X
X    sprintf(buf, "Score: %6d", score);
X    pw_text(joystick_win, 500, 22, PIX_SRC, big_font, buf);
X    pw_text(joystick_win, 500, 22, PIX_SRC|PIX_DST, big_font, buf);
X
X    if (play_mode != REAL_PLAY) {
X	pw_text(draw_win, 105, 12, PIX_SRC, small_font,
X	    "Click RIGHT mouse button or use <spacebar> to start new game.");
X	return;
X    }
X
X    pw_text(joystick_win, 500, 45, PIX_SRC, big_font, "Lives: ");
X    for (x = 0; x < MAX_LIVES; x++)
X	pw_rop(joystick_win, 575+(x*20), 32, 16,16, (x < lives-1)?
X	    PIX_SRC:PIX_CLR, &pen_image, 0, 0);
X    sprintf(buf, "Filled: %d%%",(int)((double)area_closed/TOTAL_AREA*100));
X    pw_text(draw_win, 280, 12, PIX_SRC, small_font, buf);
X    pw_text(draw_win, 281, 12, PIX_SRC|PIX_DST, small_font, buf);
X}
X
XPixrect *save[15];  /* area under text to be redisplayed upon removal of text */
Xint x_save[15], y_save, x_pos[15], y_pos[15];
Xstatic int msgs;   /* the number of text lines displayed on the board */
X
X/* print a message somewhere at the top of the playing board for two seconds */
Xmsg(fmt, args)
Xchar *fmt;
X{
X    char buf[BUFSIZ], *index();
X    register char *p2, *p = buf;
X
X    y_save = l_height(big_font) + 1;
X
X    vsprintf(buf, fmt, &args);
X#ifdef DEBUG
X    puts(buf);
X#endif DEBUG
X    do  {
X	if (p2 = index(p, '\n'))
X	    *p2 = 0;
X	x_save[msgs] = strlen(p) * l_width(big_font) + 1;
X	x_pos[msgs] = BOARD_WIDTH_IN_PIXELS/2 - x_save[msgs]/2;
X	y_pos[msgs] = TOP_BORDER + (1+msgs) * 2 * y_save;
X
X	if (!(save[msgs] = mem_create(x_save[msgs], y_save, 1))) {
X	    puts("whoops! Out of memory... no sense going on with this.");
X	    exit(1);
X	}
X	pr_rop(save[msgs], 0, 0, x_save[msgs], y_save, PIX_SRC,
X	       draw_win->pw_prretained, x_pos[msgs], y_pos[msgs]);
X
X	pw_text(draw_win, x_pos[msgs], y_pos[msgs]+l_height(big_font)-5,
X	    PIX_SRC, big_font, p);
X	pw_text(draw_win, x_pos[msgs]+1, y_pos[msgs]+l_height(big_font)-5,
X	    PIX_SRC|PIX_DST, big_font, p);
X    } while (++msgs < 15 && p2 && *(p = p2+1));
X}
X
X/* remove all messages from the board and put back the images underneith */
Xremove_msgs(clearing)
X{
X    while (msgs--) {
X	if (!clearing)
X	    pw_rop(draw_win, x_pos[msgs], y_pos[msgs], x_save[msgs],  y_save,
X		PIX_SRC, save[msgs], 0, 0);
X	pr_destroy(save[msgs]);
X    }
X    msgs = 0;
X}
X
Xcatch(sig)
X{
X    stop_timer();
X    if (sig == SIGXCPU) {
X	msg("CPU timelimit exceeded.  Go home and eat dinner.");
X	sleep(2);
X	remove_msgs(0);
X	return;
X    }
X    change_life(DIE);
X    if (sig == SIGSEGV)
X	fprintf(stderr, "Segmentation fault.\n");
X    else
X	fprintf(stderr, "Bus Error\n");
X    abort();
X}
END_OF_main.c
if test 9961 -ne `wc -c <main.c`; then
    echo shar: \"main.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f regions.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"regions.c\"
else
echo shar: Extracting \"regions.c\" \(10630 characters\)
sed "s/^X//" >regions.c <<'END_OF_regions.c'
X#include "qix.h"
X
Xshort slow_grey_dat[] = {
X#include <images/square_25.pr>
X};
Xmpr_static(slow_grey,       16, 16, 1, slow_grey_dat);
X
Xshort fast_grey_dat[] = {
X#include <images/square_50.pr>
X};
Xmpr_static(fast_grey,       16, 16, 1, fast_grey_dat);
X
X/*
X * Ther user is drawing a line ... store each move as a doubly linked
X * list of x/y coords.  When the region is completed, the list is completed
X * resulting in a closed polygon.
X */
Xadd_to_line(x, y)
Xregister int x,y;
X{
X    struct region *new;
X
X    if(!(new = (struct region *)malloc(sizeof(struct region)))) {
X	change_life(DIE);
X	fprintf(stderr, "%s, line %d: malloc failed\n", __FILE__, __LINE__);
X	abort();
X    }
X    new->x = x;
X    new->y = y;
X    new->next = (struct region *) NULL;
X    new->prev = cur_coord;
X    if (nitems++)
X	cur_coord->next = new, cur_coord = new;
X    else
X	region = new, cur_coord = region;
X}
X
X/*
X * close region means that the user has successfully drawn from
X * one point to another closing a "region" of territory.  We *should*
X *    Kill the current fuse.
X *    Determine where the qix is and determine the
X *    	region that does NOT enclose the qix (get_edge()).
X *    Call polyfill to fill region and tally up points.
X *    Fill the the region with the appropriate "shade".
X * If there are two qix, check to see that get_edge returns the same edge.
X * If they are different, then the user split the two qix.  If they're the
X * same, close the region as usual.
X *
X * return 0 if normal region closed.  return 1 on error or splitting 2 qix.
X */
Xclose_region(x,y)
X{
X    int npts[1], n, edge, region_score;
X    struct pr_pos *calloc(), *new_area, save_pt;
X
X    fuse = NULL;
X
X    if (level > -1 && (n = get_edge(moving, x, y, 1)) == -1)
X	return -1;
X    if ((edge = get_edge(moving, x, y, 0)) == -1)
X	return -1;
X    if (level > -1 && edge != n) {
X	msg("You split the two qix!");
X	sleep(2);
X	rm_cur_line(PIX_SRC); /* don't erase it, but free it up */
X	moving = STOP;
X	return 1;
X    }
X
X#ifdef DEBUG
X    if (debug && edge)
X	printf("moving = %s, edge = %s\n",
X	    (moving == UP)? "UP" : (moving == DOWN)? "DOWN" :
X	    (moving == LEFT)? "LEFT" : "RIGHT",
X	    (edge == UP)? "UP" : (edge == DOWN)? "DOWN" :
X	    (edge == LEFT)? "LEFT" : "RIGHT");
X#endif DEBUG
X
X    if (moving == UP && edge == LEFT || moving == LEFT && edge == UP)
X	region_score = polyfill(x*2 + 1, y*2 + 1);
X    else if (moving == RIGHT && edge == DOWN
X	  || moving == DOWN && edge == RIGHT)
X	region_score = polyfill(x*2 - 1, y*2 - 1);
X    else if (moving == UP && edge == RIGHT
X	  || moving == RIGHT && edge == UP)
X	region_score = polyfill(x*2 - 1, y*2 + 1);
X    else if (moving == LEFT && edge == DOWN
X	  || moving == DOWN && edge == LEFT)
X	region_score = polyfill(x*2 + 1, y*2 - 1);
X    else
X	region_score = 0;
X
X    /* region_score is number of board locations closed * 4 since there
X     * are 4 quads per square. divide region_score by 4.
X     */
X    region_score /= 4;
X
X    /* level shows bonus multipliers -- !fast is a slow draw (double score)
X     * 1/2 point per board location, so divide region_score by 2.
X     */
X    score += (region_score * ((level>-1)? (level+1) : 1) * (!fast + 1))/2;
X    area_closed += region_score;
X
X    save_pt.x = x, save_pt.y = y;
X    while (x != region->x || y != region->y) {
X	if (nitems > 10000) {
X	    msg("can't fill region; over 10000 positions");
X	    pen_x = region->x, pen_y = region->y;
X	    msg("removing bad line ...(takes a while)");
X	    rm_cur_line(XOR); /* causes dotted line effect */
X	    remove_msgs(0);
X	    return -1;
X	}
X	/* if we came from up, we check left-right */
X	add_to_line(x, y);
X#ifdef DEBUG
X	if (debug > 2)
X	    show_bert(x, y);
X#endif DEBUG
X
X	switch (moving) {
X	    when UP :
X		switch (edge) {
X		    /* Edge is on our left, sweep counter-clockwise */
X		    when LEFT :
X			if (board[x][y] & CL_LN_RT)
X			    x++, moving = RIGHT, edge = UP;
X			else if (board[x][y] & CL_LN_UP)
X			    y--;
X			else if (board[x][y] & CL_LN_LF)
X			    x--, moving = LEFT, edge = DOWN;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		    /* Edge is on our right, sweep clockwise */
X		    when RIGHT :
X			if (board[x][y] & CL_LN_LF)
X			    x--, moving = LEFT, edge = UP;
X			else if (board[x][y] & CL_LN_UP)
X			    y--;
X			else if (board[x][y] & CL_LN_RT)
X			    x++, moving = RIGHT, edge = DOWN;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		}
X
X	    when LEFT :
X		switch (edge) {
X		    /* Edge is above, sweep counter-clockwise */
X		    when UP :
X			if (board[x][y] & CL_LN_DN)
X			    y++, moving = DOWN, edge = LEFT;
X			else if (board[x][y] & CL_LN_LF)
X			    x--;
X			else if (board[x][y] & CL_LN_UP)
X			    y--, moving = UP, edge = RIGHT;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		    /* Edge is below, sweep clockwise */
X		    when DOWN :
X			if (board[x][y] & CL_LN_UP)
X			    y--, moving = UP, edge = LEFT;
X			else if (board[x][y] & CL_LN_LF)
X			    x--;
X			else if (board[x][y] & CL_LN_DN)
X			    y++, moving = DOWN, edge = RIGHT;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		}
X
X	    when DOWN :
X		switch (edge) {
X		    /* Edge is on our left, sweep clockwise */
X		    when LEFT :
X			if (board[x][y] & CL_LN_RT)
X			    x++, moving = RIGHT, edge = DOWN;
X			else if (board[x][y] & CL_LN_DN)
X			    y++;
X			else if (board[x][y] & CL_LN_LF)
X			    x--, moving = LEFT, edge = UP;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		    /* Edge is on our right, sweep counter-clockwise */
X		    when RIGHT :
X			if (board[x][y] & CL_LN_LF)
X			    x--, moving = LEFT, edge = DOWN;
X			else if (board[x][y] & CL_LN_DN)
X			    y++;
X			else if (board[x][y] & CL_LN_RT)
X			    x++, moving = RIGHT, edge = UP;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		}
X
X	    when RIGHT :
X		switch (edge) {
X		    /* Edge is above, sweep clockwise */
X		    when UP :
X			if (board[x][y] & CL_LN_DN)
X			    y++, moving = DOWN, edge = RIGHT;
X			else if (board[x][y] & CL_LN_RT)
X			    x++;
X			else if (board[x][y] & CL_LN_UP)
X			    y--, moving = UP, edge = LEFT;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		    /* Edge is below, sweep counter-clockwise */
X		    when DOWN :
X			if (board[x][y] & CL_LN_UP)
X			    y--, moving = UP, edge = RIGHT;
X			else if (board[x][y] & CL_LN_RT)
X			    x++;
X			else if (board[x][y] & CL_LN_DN)
X			    y++, moving = DOWN, edge = LEFT;
X#ifdef DEBUG
X			else
X			    bad_fill_cell(x,y, edge, moving);
X#endif DEBUG
X		}
X	}
X    }
X
X    if (!(new_area = calloc(nitems, sizeof(struct pr_pos)))) {
X	change_life(DIE);
X	fprintf(stderr, "%s, line %d: malloc failed\n", __FILE__, __LINE__);
X	abort();
X    }
X
X    /* we CAN move onto endpoints, but nothing inside */
X    npts[0] = nitems;
X    for (n = 0; region; n++) {
X	new_area[n].x = convert_x(region->x);
X	new_area[n].y = convert_y(region->y);
X	board[region->x][region->y] &= ~NEW_LINE;
X	board[region->x][region->y] |= OLD_LINE;
X	cur_coord = region->next;
X	free(region);
X	region = cur_coord;
X    }
X#if 0
X    if (debug > 1)
X	printf("polyfill(): %d; polygon_area(): %d\n", region_score,
X		polygon_area(new_area, nitems) / LINE_SPACE / LINE_SPACE);
X#endif
X
X    toggle_sparks();
X    pw_polygon_2(draw_win, 0,0,1, npts, new_area, PIX_SRC | PIX_DST,
X	fast? &fast_grey : &slow_grey,0,0);
X    toggle_sparks();
X
X    free(new_area);
X    nitems = 0, moving = STOP;
X    if (play_mode == DEMO)
X	time_left = 1;
X    return 0;
X}
X
X#ifdef DEBUG
Xbad_fill_cell(x, y, edge, moving)
Xregister int x, y, edge, moving;
X{
X    msg("fail at %d, %d (%x) moving = %s, edge on %s", x,y,board[x][y],
X	(moving == UP)? "up" : (moving == DOWN)? "down" :
X	(moving == RIGHT)? "right" : "left",
X	(edge == UP)? "up" : (edge == DOWN)? "down" :
X	(edge == RIGHT)? "right" : "left");
X    sleep(2);
X    remove_msgs(0);
X}
X#endif DEBUG
X
Xrm_cur_line(op)
X{
X    if (region)
X	board[region->x][region->y] = saved_edge;
X    while (cur_coord)
X	if (cur_coord = cur_coord->prev) {
X	    board[cur_coord->next->x][cur_coord->next->y] = 0;
X	    draw(convert_x(cur_coord->next->x),
X		 convert_y(cur_coord->next->y),
X		 convert_x(cur_coord->x), convert_y(cur_coord->y), op);
X	    free(cur_coord->next);
X	}
X    region = (struct region *)NULL;
X    cur_coord = (struct region *)NULL;
X    nitems = 0;
X}
X
X/* cmp: returns 0, 1, or 2 depending on whether
X	a is    <, =, or > b */
X#define cmp(a,b) ((a > b) + (a >= b))
X/* which way bert should start, depending on where person is w.r.t qix */
Xchar dirtable[3][3] ={	{ LEFT, UP, UP },
X			{ LEFT, 0, RIGHT},
X			{ DOWN, DOWN, RIGHT} };
Xget_edge(person_moving, person_x, person_y, which_qix)
X{
X    int dx, dy;
X    int x, y, moving;
X
X    if (get_qix_pos(which_qix, &x, &y) == -1)
X	return -1;
X
X    /* move from the qix until we find a line or the edge of the board */
X    moving = dirtable[cmp(person_y, y)][cmp(person_x, x)];
X    if (moving == 0) {
X	change_life(DIE);
X	msg("You fucked up so incredibly badly that you must die\n");
X	exit(1);
X    }
X    dx = dy = 0;
X    switch (moving) {
X	when UP: dy = -1;
X	when DOWN: dy = 1;
X	when LEFT: dx = -1;
X	when RIGHT: dx = 1;
X    }
X    while (!board[x][y]) {
X#ifdef DEBUG
X	show_bert(x, y);
X#endif DEBUG
X	x += dx;
X	y += dy;
X    }
X
X    /* now traverse the interior clockwise until bert hits the person */
X    for (;;) {
X	int on_person = person_x == x && person_y == y;
X#ifdef DEBUG
X	show_bert(x, y);
X#endif DEBUG
X	/* always sweep clockwise around the edges till we find the player */
X	if (on_person && moving == person_moving)
X	    /* the bert just rear-ended player */
X       /* qix on on the "right" of the player (with respect to player facing) */
X	    return RIGHT_OF(person_moving);
X
X	switch (moving) {
X	    when UP :
X		if (board[x][y] & CL_LN_RT)
X		    x++, moving = RIGHT;
X		else if (board[x][y] & CL_LN_UP)
X		    y--;
X		else if (board[x][y] & CL_LN_LF)
X		    x--, moving = LEFT;
X
X	    when LEFT :
X		if (board[x][y] & CL_LN_UP)
X		    y--, moving = UP;
X		else if (board[x][y] & CL_LN_LF)
X		    x--;
X		else if (board[x][y] & CL_LN_DN)
X		    y++, moving = DOWN;
X
X	    when DOWN :
X		if (board[x][y] & CL_LN_LF)
X		    x--, moving = LEFT;
X		else if (board[x][y] & CL_LN_DN)
X		    y++;
X		else if (board[x][y] & CL_LN_RT)
X		    x++, moving = RIGHT;
X
X	    when RIGHT :
X		if (board[x][y] & CL_LN_DN)
X		    y++, moving = DOWN;
X		else if (board[x][y] & CL_LN_RT)
X		    x++;
X		else if (board[x][y] & CL_LN_UP)
X		    y--, moving = UP;
X	}
X	if (on_person && moving == OPP_OF(person_moving)) {
X	    /* then bert just ran over player */
X       /* qix on on the "left" of the player (with respect to player facing) */
X	    return LEFT_OF(person_moving);
X        }
X    }
X}
END_OF_regions.c
if test 10630 -ne `wc -c <regions.c`; then
    echo shar: \"regions.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f score.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"score.c\"
else
echo shar: Extracting \"score.c\" \(3305 characters\)
sed "s/^X//" >score.c <<'END_OF_score.c'
X/*  SCORE.C  */
X
X#include "qix.h"
X#include <sys/fcntl.h>
X
X#define NAMELEN		3
X
Xstruct scores {
X    int score;
X    char initials[NAMELEN+1];
X    char login[9];
X}   top_ten[10];
X
Xextern int errno;
Xextern char *sys_errlist[];
Xextern char *sprintf();
X
Xscore_board(Read, names)
X{
X    struct scores *scp, *temp;
X    char buf[BUFSIZ];
X    int fd;
X
X    clear_board();
X
X    for (scp = top_ten; scp < &top_ten[10]; scp++) {
X	(void) strcpy(scp->initials, "Qix");
X	scp->initials[3] = 0;
X	(void) strcpy(scp->login, "computer");
X#ifdef DEBUG
X	scp->score = 0;
X#else DEBUG
X	scp->score = 30000;
X#endif DEBUG
X    }
X
X    /* read the top ten file into the array and close the file */
X    if ((fd = open(SCOREFILE, O_RDWR)) == -1 ||
X	read(fd, (char *) top_ten, sizeof(top_ten)) == -1) {
X	msg("No score file:\n%s", sys_errlist[errno]);
X	sleep(2);
X	remove_msgs(0);
X	return;
X    }
X
X    /* Print the list */
X    if (Read) {
X	msg("Top Players:\nScore%24cName\n", ' ');
X	for (scp = top_ten; scp < &top_ten[10] && scp->score; scp++) {
X	    (void) sprintf(buf, "%7.d%24c%c%c%c  ", scp->score, ' ',
X		scp->initials[0], scp->initials[1], scp->initials[2]);
X	    if (names)
X		(void) strcat(buf, scp->login);
X	    msg(buf);
X	}
X    }
X    /* check to see if current score made it */
X    else {
X	int pos;
X	for (pos = 1, scp = top_ten; pos <= 10; scp++, pos++)
X	    if (scp->score < score)
X		break;
X	if (pos <= 10) {
X	    char *getlogin(), *login = getlogin();
X
X	    for (temp = &top_ten[9]; temp > scp; temp--)
X		*temp = *(temp - 1);
X	    scp->score = score;
X	    (void) strcpy(scp->login, login);
X	    prompt_initials(pos, scp->initials);
X	    if (strlen(scp->initials) > 1) {
X		(void) lseek(fd, (long)0, 0);
X		(void) write(fd, (char *)top_ten, sizeof top_ten);
X	    }
X	}
X    }
X    (void) close(fd);
X}
X
Xchar *
Xordinate(n)
X{
X    if (n == 1)
X	return "st";
X    if (n == 2)
X	return "nd";
X    if (n == 3)
X	return "rd";
X    return "th";
X}
X
Xprompt_initials(pos, buf)
Xregister char *buf;
X{
X    Event event;
X    int x = MID_X - 15 * l_width(big_font);
X    int y = 19 * l_height(big_font), len;
X    char s[16];
X
X    msg("You attained the %d%s position", pos, ordinate(pos));
X    msg("Type initials or use:\nLEFT button to advance one character.");
X    msg("MIDDLE button to decrement one character.\n");
X    msg("Use RETURN or RIGHT button to enter each letter.");
X    msg("Use <backspace> key to go back one position.");
X    pw_text(draw_win, x, y, PIX_SRC, big_font, sprintf(s, "%d", score));
X    x += 25 * l_width(big_font);
X    (void) strcpy(buf, "AAA");
X
X    for (len = 0; len < 3;) {
X	pw_text(draw_win, x - len*l_width(big_font), y, PIX_SRC, big_font, buf);
X	pw_char(draw_win, x, y, PIX_SRC|PIX_DST, big_font, '_');
X
X	do window_read_event(Draw, &event);
X	while (event.ie_code == LOC_MOVE || event.ie_code == LOC_DRAG ||
X	       event_is_up(&event));
X
X	switch (event.ie_code) {
X	    when 8 : case 127 :
X		if (len > 0)
X		    len--, x -= l_width(big_font);
X	    when '\n' : case '\r' : case MS_RIGHT :
X		len++, x += l_width(big_font);
X	    when MS_LEFT :
X		if (++(buf[len]) < 'A' || buf[len] > 'z')
X		    buf[len] = 'A';
X	    when MS_MIDDLE :
X		if (--(buf[len]) < 'A' || buf[len] > 'z')
X		    buf[len] = 'z';
X	    otherwise :
X		if (isascii(event.ie_code))
X		    buf[len] = (char)event.ie_code;
X		else
X		    printf("%d ", event.ie_code);
X	}
X    }
X}
END_OF_score.c
if test 3305 -ne `wc -c <score.c`; then
    echo shar: \"score.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sparks.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sparks.c\"
else
echo shar: Extracting \"sparks.c\" \(8809 characters\)
sed "s/^X//" >sparks.c <<'END_OF_sparks.c'
X#include "qix.h"
X
X/*
X * This file deals with the sparks excplicitely.  A fuse is a spark, but
X * travels along the the line the user is drawing.
X */
X
Xshort spark1_dat[] = {
X#include "spark1.pr"
X};
Xmpr_static(spark1,     16, 16, 1, spark1_dat);
X
Xshort spark2_dat[] = {
X#include "spark2.pr"
X};
Xmpr_static(spark2,     16, 16, 1, spark2_dat);
X
Xshort spark3_dat[] = {
X#include "spark3.pr"
X};
Xmpr_static(spark3,     16, 16, 1, spark3_dat);
X
Xshort spark4_dat[] = {
X#include "spark4.pr"
X};
Xmpr_static(spark4,     16, 16, 1, spark4_dat);
X
Xstatic Pixrect *spark_icons[4] = { &spark1, &spark2, &spark3, &spark4 };
Xstatic int spark_time, aggressive;
X
X/*
X * Macor to draw a spark at x,y -- intended to call this macro twice with
X * the same x,y coords to remove the first spark icon. There are four spark
X * icons to give a "sparkling" effect when it moves. Since sparks can only
X * move left-right or up-down the formula given finds which icon to use to
X * to guarantee that it's not the last one used.
X */
X#define draw_spark(x, y) 	\
X    pw_rop(draw_win, pen_coord_x(x), pen_coord_y(y), 16,16, \
X	XOR, spark_icons[(x + y) & 3], 0,0)
X
Xstruct spark {
X    int x, y, oldx, oldy;
X} sparks[] = {
X    { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
X    { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
X    { -1, -1, -1, -1 }, { -1, -1, -1, -1 }
X};
Xint MAX_SPARKS = sizeof (sparks) / sizeof (struct spark);
X
X#define CLOCKWISE(spark_number) (spark_number & 1)
X
X/* start a new spark at this x,y coord.  Since sparks are released in
X * pairs, odd spark goes left, even spark goes right, and those directions
X * are [supposed] to remain with the spark thruout its life.
X */
Xstart_spark(x, y)
X{
X    register int sp;
X
X#ifdef DEBUG
X    if (debug > 1)
X	return;
X#endif DEBUG
X
X    for (sp = 0; sp < MAX_SPARKS; sp++)
X	if (sparks[sp].x < 0) {
X	    if (CLOCKWISE(sp)) /* odd number spark */
X		sparks[sp].oldx = x-1, sparks[sp].oldy = y;
X	    else
X		sparks[sp].oldx = x+1, sparks[sp].oldy = y;
X	    sparks[sp].x = x, sparks[sp].y = y;
X	    return;
X	}
X}
X
X/*
X * Spark movement checks... can't move back onto himself... must only move
X * onto a square which has a connecting line.  If it's on a square which
X * is completely painted, it may move anywhere.  Otherwise, the square has
X * to have at least one quad which is not painted.  Sparks may only move
X * on "old" (not currently being drawn) lines unless they are aggressive.
X */
X#define check_up(curx, cury, newx, newy, oldy) \
X    (newy != oldy && (board[curx][cury] & CL_LN_UP) && \
X    (aggressive || (board[newx][newy] & OLD_LINE) && \
X    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))
X
X#define check_down(curx, cury, newx, newy, oldy) \
X    (newy != oldy && (board[curx][cury] & CL_LN_DN) && \
X    (aggressive || (board[newx][newy] & OLD_LINE) && \
X    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))
X
X#define check_left(curx, cury, newx, newy, oldx) \
X    (newx != oldx && (board[curx][cury] & CL_LN_LF) && \
X    (aggressive || (board[newx][newy] & OLD_LINE) && \
X    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))
X
X#define check_right(curx, cury, newx, newy, oldx) \
X    (newx != oldx && (board[curx][cury] & CL_LN_RT) && \
X    (aggressive || (board[newx][newy] & OLD_LINE) && \
X    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))
X
X/* return -1 if player dies.  0 otherwise. */
Xmove_sparks()
X{
X    register int x, y, sp, move_clockwise, came_from, dir;
X    /* new spark x and y coord */
X
X    for (sp = 0; sp < MAX_SPARKS; sp++) {
X	if (sparks[sp].x < 0)
X	    break;
X	/* if the spark was just introduced, this will not erase the spark,
X	 * but actually create two images.  however, since sparks are intro-
X	 * duced in pairs, the second spark will have the same coords and
X	 * erase this mark. (clever, huh?)
X	 */
X	draw_spark(sparks[sp].x, sparks[sp].y);
X	x = sparks[sp].x, y = sparks[sp].y;
X	/* user bit the big one */
X	if (x == pen_x && y == pen_y) {
X	    draw_spark(sparks[sp].x, sparks[sp].y); /* redraw the spark */
X	    change_life(DIE);
X	    return -1;
X	}
X
X	came_from = (x > sparks[sp].oldx)? LEFT :
X		    (x < sparks[sp].oldx)? RIGHT :
X		    (y > sparks[sp].oldy)? UP : DOWN;
X	if (check_painted(x, y, PAINTED))
X	    move_clockwise = (random() & 1);
X	else {
X	    move_clockwise = (CLOCKWISE(sp));
X	    if (check_painted(sparks[sp].oldx, sparks[sp].oldy, PAINTED))
X	    /* we just exited a painted region onto open territory.
X	     * pretend we came from along a border, as usual.
X	     */
X		while (came_from == UP && check_painted(x,y, CL_PNT_TOP) ||
X		       came_from == DOWN && check_painted(x,y, CL_PNT_BOT) ||
X		       came_from == LEFT && check_painted(x,y, CL_PNT_LEFT) ||
X		       came_from == RIGHT && check_painted(x,y, CL_PNT_RIGHT))
X		    if (CLOCKWISE(sp))
X			came_from = LEFT_OF(came_from);
X		    else
X			came_from = RIGHT_OF(came_from);
X	}
X	dir = came_from;
X
X	/* if we are not on a border (surrounded by painted quads) */
X	do  {
X	    if (move_clockwise)
X		dir = LEFT_OF(dir); /* this is right, don't argue */
X	    else
X		dir = RIGHT_OF(dir);
X#ifdef DEBUG
X	    if (dir == came_from) {
X		box(convert_x(x)-10, convert_y(y)-10,
X		    convert_x(x)+10, convert_y(y)+10, XOR);
X		msg("HALT! infinite-loop police! [y] (%d, %d)", x, y);
X		sleep(2);
X		remove_msgs(0);
X		box(convert_x(x)-10, convert_y(y)-10,
X		    convert_x(x)+10, convert_y(y)+10, XOR);
X		break;
X	    }
X#endif DEBUG
X	    switch (dir) {
X		when LEFT:
X		    if (check_left(x, y, x - 1, y, sparks[sp].oldx))
X			x--;
X		when RIGHT:
X		    if (check_right(x,y,x+1,y,sparks[sp].oldx))
X			x++;
X		when UP:
X		    if (check_up(x,y,x,y-1,sparks[sp].oldy))
X			y--;
X		when DOWN:
X		    if (check_down(x, y, x, y+1, sparks[sp].oldy))
X			y++;
X	    }
X	} while (x == sparks[sp].x && y == sparks[sp].y);
X
X	sparks[sp].oldx = sparks[sp].x, sparks[sp].oldy = sparks[sp].y;
X	/* draw the new spark */
X	draw_spark(x, y);
X	sparks[sp].x = x, sparks[sp].y = y;
X
X	if (x == pen_x && y == pen_y) {
X	    change_life(DIE);
X	    return -1;
X	}
X    }
X    /* if the timeout has occured, release two sparks */
X    if (spark_time-- <= 0) {
X	spark_time = SPARK_TIME;
X	if (sp >= MAX_SPARKS/2) {
X	    if (!aggressive) {
X		/* give the only warning we can without a sound chip :-) */
X		fputc(7, stderr), fflush(stderr);
X		msg("Sparx are now aggressive.");
X		sleep(2);
X		remove_msgs(0);
X		aggressive = 1;
X	    }
X	    if (sp == MAX_SPARKS)
X		return 0; /* no sparks left to start, so don't do a countdown */
X	}
X	start_spark(BOARD_WIDTH/2, 0, TRUE);
X	start_spark(BOARD_WIDTH/2, 0, FALSE);
X	draw(BORDER, 20, BOARD_WIDTH_IN_PIXELS-BORDER, 20, PIX_SRC);
X	draw(BORDER, 21, BOARD_WIDTH_IN_PIXELS-BORDER, 21, PIX_SRC);
X    }
X    if (sp < MAX_SPARKS) {
X	/* calculate the percentage of the width of the board in pixels */
X	register int len = (((spark_time*100)/SPARK_TIME)) *
X	       (BOARD_WIDTH_IN_PIXELS-2*BORDER)/200;
X
X	draw(BORDER, 20, BOARD_WIDTH_IN_PIXELS/2 - len, 20, PIX_CLR);
X	draw(BORDER, 21, BOARD_WIDTH_IN_PIXELS/2 - len, 21, PIX_CLR);
X	draw(BOARD_WIDTH_IN_PIXELS/2 + len, 20,
X	     BOARD_WIDTH_IN_PIXELS-BORDER, 20, PIX_CLR);
X	draw(BOARD_WIDTH_IN_PIXELS/2 + len, 21,
X	     BOARD_WIDTH_IN_PIXELS-BORDER, 21, PIX_CLR);
X    }
X    return 0;
X}
X
X/*
X * move fuse -- first, remove the last location (if applicable). If
X * the fuse has burned out, then programmer just wants to erase last one.
X * next, since the fuse only travels along new lines, move down the list.
X */
Xmove_fuse(pos)
Xregister struct region **pos;
X{
X    static x = -1, y;
X    int n;
X
X    if (x > -1)
X	draw_spark(x, y);
X    if (!pos || !*pos) {
X	x = -1;
X	return 0;
X    }
X    draw_spark((*pos)->x, (*pos)->y);
X    x = (*pos)->x, y = (*pos)->y;
X
X    if ((*pos)->x == pen_x && (*pos)->y == pen_y) {
X	change_life(DIE);
X	pen_x = region->x, pen_y = region->y;
X	return -1;
X    }
X    if (!(*pos = (*pos)->next))
X	*pos = NULL, x = -1;
X    return 0;
X}
X
X/*
X * removes all sparks from the screen and their x/y coords.
X * reset the sparktime value and draw the timeout line.
X */
Xclear_sparks()
X{
X    int n;
X
X    /* for each spark, if active, make it go away and reset to -1 */
X    for (n = 0; n < MAX_SPARKS; n++)
X	if (sparks[n].x > -1) {
X	    draw_spark(sparks[n].x, sparks[n].y);
X	    sparks[n].oldx = sparks[n].x = -1;
X	}
X    draw(BORDER, 20, BOARD_WIDTH_IN_PIXELS-BORDER, 20, PIX_CLR);
X    draw(BORDER, 21, BOARD_WIDTH_IN_PIXELS-BORDER, 21, PIX_CLR);
X    aggressive = spark_time = 0;
X}
X
X/* routine to turn on/off all sparks.  When user closes a region, call
X * this routine to turn off sparks so when the region is filled, the
X * spark doesn't leave it's mark once it starts moving again.
X */
Xtoggle_sparks()
X{
X    register int sp;
X
X    for (sp = 0; sp < MAX_SPARKS; sp++) {
X	if (sparks[sp].x < 0)
X	    break;
X	draw_spark(sparks[sp].x, sparks[sp].y);
X    }
X}
END_OF_sparks.c
if test 8809 -ne `wc -c <sparks.c`; then
    echo shar: \"sparks.c\" unpacked with wrong size!
fi
# end of overwriting check
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