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