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