DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T j

⟦1e759b8cc⟧ TextFile

    Length: 21409 (0x53a1)
    Types: TextFile
    Names: »joystick.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Qix/joystick.c« 

TextFile

#include "qix.h"
#include "math.h"

#ifdef X11
#include	"pen.xbm",
#include	"mse.lf.gr.xbm",
#include	"mse.lf.xbm",
#include	"mse.mid.gr.xbm",
#include	"mse.mid.xbm",
#include	"mse.rt.icon.xbm",
#include	"jstick.lf.xbm",
#include	"jstick.rt.xbm",
#include	"jstick.up.xbm",
#include	"jstick.dn.xbm",
#include	"jstick.stop.xbm"

Pixmap
    joystick_left, joystick_right, joystick_up, joystick_down,
    joystick_stop, ready_icon, ms_fast_on, ms_fast_off, ms_slow_on,
    ms_slow_off, pen_image;

struct image_stuff {
    Pixmap *image;
    int w, h;
    char *bits;
};

struct image_stuff images[] = {
    { &pen_image,
	pen_width, pen_height, pen_bits },
    { &ms_fast_on,
	mse_lf_gr_width, mse_lf_gr_height, mse_lf_gr_bits },
    { &ms_fast_off,
	mse_lf_width, mse_lf_height, mse_lf_bits },
    { &ms_slow_on,
	mse_mid_gr_width, mse_mid_gr_height, mse_mid_gr_bits },
    { &ms_slow_off,
	mse_mid_width, mse_mid_height, mse_mid_bits },
    { &ready_icon,
	mse_rt_icon_width, mse_rt_icon_height, mse_rt_icon_bits },
    { &joystick_left,
	jstick_lf_width, jstick_lf_height, jstick_lf_bits },
    { &joystick_right,
	jstick_rt_width, jstick_rt_height, jstick_rt_bits },
    { &joystick_up,
	jstick_up_width, jstick_up_height, jstick_up_bits },
    { &joystick_down,
	jstick_dn_width, jstick_dn_height, jstick_dn_bits },
    { &joystick_stop,
	jstick_stop_width, jstick_stop_height, jstick_stop_bits },
};

init_images()
{
    int i;
    Pixmap pix;
    int scr = DefaultScreen(dpy);

    for (i = 0; i < sizeof(images) / sizeof (struct image_stuff); i++)
	if (!(*images[i].image = XCreatePixmapFromBitmapData(dpy, draw_win,
	    images[i].bits, images[i].w, images[i].h,
	    BlackPixel(dpy, scr), WhitePixel(dpy, scr),
	    DefaultDepth(dpy, scr))))
	    perror("init_images"), exit(1);

    init_sparx();
    init_gray();
}

#else
/* the pen marker */
short marker_curs_dat[] = {
#include "marker.cursor"
};
mpr_static(_pen_image,          16, 16, 1, marker_curs_dat);
Pixrect *pen_image = &_pen_image;

short fast_draw_off_dat[] = {
#include <images/mouse_left_hand.pr>
};
mpr_static(_ms_fast_off,      16, 23, 1, fast_draw_off_dat);
Pixrect *ms_fast_off = &_ms_fast_off;

short fast_draw_on_dat[] = {
#include <images/mouse_left_hand_grey.pr>
};
mpr_static(_ms_fast_on,     16, 23, 1, fast_draw_on_dat);
Pixrect *ms_fast_on = &_ms_fast_on;

short slow_draw_off_dat[] = {
#include <images/mouse_mid_hand.pr>
};
mpr_static(_ms_slow_off,      16, 23, 1, slow_draw_off_dat);
Pixrect *ms_slow_off = &_ms_slow_off;

short slow_draw_on_dat[] = {
#include <images/mouse_mid_hand_grey.pr>
};
mpr_static(_ms_slow_on,     16, 23, 1, slow_draw_on_dat);
Pixrect *ms_slow_on = &_ms_slow_on;

/* joystick (really, arrow) symbols */
short left_arrow_dat[] = {
#include "joystick.lf"
};
mpr_static(_joystick_left,   64, 64, 1, left_arrow_dat);
Pixrect *joystick_left = &_joystick_left;

short right_arrow_dat[] = {
#include "joystick.rt"
};
mpr_static(_joystick_right,  64, 64, 1, right_arrow_dat);
Pixrect *joystick_right = &_joystick_right;

short up_arrow_dat[] = {
#include "joystick.up"
};
mpr_static(_joystick_up,     64, 64, 1, up_arrow_dat);
Pixrect *joystick_up = &_joystick_up;

short dn_arrow_dat[] = {
#include "joystick.dn"
};
mpr_static(_joystick_down,   64, 64, 1, dn_arrow_dat);
Pixrect *joystick_down = &_joystick_down;

/* a circle with line thru it */
short stop_dat[] = {
#include "joystick.stop"
};
mpr_static(_joystick_stop,   64, 64, 1, stop_dat);
Pixrect *joystick_stop = &_joystick_stop;

/* a big right mouse button */
short ready_icon_dat[] = {
#include "mouse.rt.icon"
};
mpr_static(_ready_icon,      64, 64, 1, ready_icon_dat);
Pixrect *ready_icon = &_ready_icon;
#endif /* X11 */

/*
 * the main window selection catches input interrupts and calls this
 * routine to process what just happened.  Nothing is actually done
 * besides that -- that is, the pen is not moved, the qix isn't moved,
 * and sparks don't move.  however, we will reset the "moving" variable,
 * start the or finish the "drawing" state, and reset the icon that displays
 * the joystick icon that indicates which way the user is moving.
 */
move_joystick(canvas, event)
register Canvas canvas;
register Event *event;
{
    register int ID;
    static start_fast;
    int x, y; /* event location */

#ifdef X11
    int release = FALSE;
#define event_is_up(e)	(release == TRUE)

    switch(event->xany.type) {
	case KeyRelease : release = TRUE;
	case KeyPress : {
	    char b;
	    KeySym k; /* ignored */
	    (void) XLookupString(event, &b, 1, &k, NULL);
	    ID = (int)(b);
#ifdef DEBUG
	    if (debug)
		putchar(ID), fflush(stdout);
#endif /* DEBUG */
	    x = MID_X, y = MID_Y; /* no movement by user */
	    break;
	}
	case MotionNotify :
	    ID = LOC_MOVE;
	    x = event->xmotion.x, y = event->xmotion.y;
#ifdef DEBUG
	    if (debug)
		putchar('.'), fflush(stdout);
#endif /* DEBUG */
	    /*
	    while (XPending(dpy) && XPeekEvent(dpy, event))
		if (event->xany.type != MotionNotify) {
		    printf("pending: %d\n", event->xany.type);
		    break;
		} else {
		    XNextEvent(dpy, event);
		    putchar('.'), fflush(stdout);
		}
	    */
	    break;
	case ButtonRelease : release = TRUE;
	case ButtonPress :
	    ID = MS_LEFT + event->xbutton.button - 1;
	    x = event->xbutton.x, y = event->xbutton.y; 
#ifdef DEBUG
	    if (debug)
		printf("Button %d %sed\n", event->xbutton.button,
		    release? "release" : "press");
#endif /* DEBUG */
	    break;
	default :
	    printf("unknown event: %d\n", event->xany.type);
	    return;
    }
#else
    ID = event->ie_code;
    x = event_x(event);
    y = event_y(event);
#endif /* X11 */
    if (play_mode != REAL_PLAY && ID != ' ' && ID != MS_RIGHT)
	return;

    if (ID == LOC_MOVE && moving != NO_MOVE) {
	register int delta_x, delta_y;
	if (x <= 0)
	    x = 1;
	if (y <= 0)
	    y = 1;
	delta_x = x - MID_X;
	delta_y = y - MID_Y;

	/* didn't move enough */
	if (abs(delta_x) <= SENS_FACTOR && abs(delta_y) <= SENS_FACTOR)
	    return;

	if (abs(delta_x) > abs(delta_y))
	    if (delta_x > 0)
		moving = RIGHT;
	    else
		moving = LEFT;
	else
	    if (delta_y > 0)
		moving = DOWN;
	    else
		moving = UP;
    }

    if (isascii(ID) && ID != ' ') {
#ifdef DEBUG
	if (isdigit(ID)) {
	    debug = ID - '0';
	    msg("Debugging level set to %d", debug);
	    Sleep(2);
	    remove_msgs();
	    return;
	} else
#endif DEBUG
	if (event_is_up(event)) {
	    /* up events -- user released a key, so stop moving */
	    /* unimplemented -- holding key down results in fast up/down's */
	    moving = STOP;
	    drawing = 0;
	    return;
	}
#ifdef X11
	else if (isupper(ID))
#else
	else if (event_shift_is_down(event))
#endif /* X11 */
	    fast = drawing = 1;
	else
	    drawing = 0;
    }

    switch(ID) {
	when MS_LEFT :
	    fast = (drawing = (!event_is_up(event)));
	    start_fast = TRUE;
	    return;
	when MS_MIDDLE :
	    fast = 0;
	    if (start_fast == TRUE && region)
		drawing = 0;
	    else
		drawing = !event_is_up(event);
	    return;
	when MS_RIGHT : case ' ' :
	    if (event_is_up(event))
		break;
	    /* if moving == NO_MOVE, RIGHT, LEFT, UP or DOWN */
	    if (!is_alive || play_mode != REAL_PLAY) {
		lives = 0;
		play_mode = REAL_PLAY;  /* set Nowhere else but here! */
		change_life(LIVE); /* "next" life in current game */
	    } else if (moving != STOP) {
		/* NO_MOVE state goes right to STOP state */
		if (moving == NO_MOVE)
		    reset_joystick_win(FALSE);
		/* all other directions go right to STOP state */
		moving = STOP;
	    } else
		/* STOP state goes right to NO_MOVE state */
		moving = NO_MOVE, reset_joystick_win(TRUE);
	when 'h' : case 'H' :
	    moving = LEFT;
	when 'l' : case 'L' :
	    moving = RIGHT;
	when 'j' : case 'J' :
	    moving = DOWN;
	when 'k' : case 'K' :
	    moving = UP;
	when LOC_MOVE : ; /* let those thru! (break-- do nothing) */
	when 3 : /* CTRL(C) */
	    drawing = 0;		
	    if (play_mode == REAL_PLAY) {
		lives = 0;
		change_life(DIE);
	    }
#ifdef DEBUG
	when '@' : no_qix_kill = !no_qix_kill; drawing = 0;
	when '#' : clear_sparks();
	when '+' : lives = min(lives+1, MAX_LIVES); update_score(); drawing = 0;
	when '-' : lives = max(lives-1, 1); update_score(); drawing = 0;
	when '!' : drawing = 0;
	    if (play_mode == REAL_PLAY) {
		lives = 0;
		change_life(LIVE);
	    } /* fall thru */
#endif DEBUG
	default :
	    return; /* do nothing */
    }
    if (moving != NO_MOVE && (x != MID_X || y != MID_Y))
#ifdef X11
	XWarpPointer(dpy, canvas, canvas, x, y,
	    BOARD_WIDTH_IN_PIXELS, BOARD_HEIGHT_IN_PIXELS+70, MID_X, MID_Y);
#else
	window_set(canvas, WIN_MOUSE_XY, MID_X, MID_Y, 0);
#endif /* X11 */
}

/*
 * The main routine waits for input from the user until an alarm goes off
 * which says, "ok, go to the next state of the machine" which may very
 * well be "do nothing".  The timer is restarted when we're done processing
 * whatever we have to process.  This is where the pen actually moves to the
 * next position, drawing lines, or running scared from a vicious spark.
 */
move_pen()
{
    register int x = pen_x, y = pen_y, new_value, old_value;
    static slow_draw;

    stop_timer();
    if (!is_alive && lives > 0) {
	/* user has died and is waiting to start again */
	Sleep(2);
	change_life(LIVE);
	stop_timer(); /* change_life restarts it */
	msg("Ready?");
	Sleep(2);
	remove_msgs(0);
	start_timer();
	return;
    }
    /* don't play if the joystick isn't active */
    if (moving == NO_MOVE || play_mode != REAL_PLAY) {
	if (play_mode != REAL_PLAY) {
	    time_left--;
	    if (play_mode == DEMO && lives > 0) {
		if (time_left == 0) {
		    int lastmove = moving;
		    register int left, right, up, down;
		    drawing = 1;
		    if (!(board[x][y] & NEW_LINE))
			fast = (rrand() & 3);
		    left = (!check_painted(x, y, CL_PNT_LEFT) &&
			    !(board[x-1][y] & NEW_LINE));

		    right = (!check_painted(x, y, CL_PNT_RIGHT) &&
			     !(board[x+1][y] & NEW_LINE));

		    up = (!check_painted(x, y, CL_PNT_TOP) &&
			  !(board[x][y-1] & NEW_LINE));

		    down = (!check_painted(x, y, CL_PNT_BOT) &&
			    !(board[x][y+1] & NEW_LINE));

		    if (!left && !right && !up && !down)
			moving = STOP, time_left = -1; /* let fuse catch up */
		    else {
			int dx = region ? region->x - x : 0;
			int dy = region ? region->y - y : 0;
			time_left = 15 + (rrand() & 31);
			/* first attempt to limit box to less than 25 X 25 */
			if (region && (_ABS(dx) > 25 || _ABS(dy) > 25)) {
			    if (_ABS(dx) > 25 ||
				_ABS(dy) > 25 && (moving == LEFT ||
						  moving == RIGHT))
				if (moving != LEFT && moving != RIGHT)
				    moving = (dx > 25) ? RIGHT : LEFT;
				else
				    moving = (dy > 0) ? DOWN : UP;
			    else if (_ABS(dy) > 25)
				if (moving != UP && moving != DOWN)
				    moving = (dy > 25) ? DOWN : UP;
				else
				    moving = (dx > 0) ? RIGHT : LEFT;
			}
			/* Make sure we can move in that direction */
			while (moving == lastmove ||
			    !left && moving == LEFT || !up && moving == UP ||
			    !down && moving == DOWN || !right && moving== RIGHT)
			    moving = LEFT + (rrand() & 3);
		    }
		}
	    } else if (time_left <= 0) {
		drawing = 0;
		level = -2;
		moving = NO_MOVE;
		init_qix();
		switch (play_mode = (play_mode + 1) % (DEMO+1)) {
		    when SHOW_SCORES :
			clear_board();
			score_board(TRUE, FALSE);
			time_left = 50;
		    when SHOW_POINTS :
			score = 0;
			move_fuse(fuse = NULL); /* just in case */
			rm_cur_line(PIX_CLR);
			clear_board();
			place_pen();
			msg("Direct the mouse to control joystick.");
			time_left = 315;
			moving = LEFT;
		    when SHOW_QIX :
			remove_msgs(0);
			msg("Your Enemies:");
			Sleep(2);
			time_left = 40;
		    when SHOW_SPARKS :
			time_left = 90;
		    when SHOW_FUSE :
			drawing = fast = 1;
			moving = UP;
			time_left = 280;
		    when SHOW_SPIRAL :
			moving = STOP;
			drawing = 0;
			time_left = 100;
		    when DEMO :
			time_left = 1;
			change_life(LIVE);
			stop_timer();
	    msg("Enclose more than\n75%%\nof the play area for extra bonus.");
			Sleep(2);
			remove_msgs(0);
			level = -2;
			drawing = fast = 1;
			goto done;
		}
	    } else switch (play_mode) {
		when SHOW_QIX :
		    move_qix();
		    if (time_left == 1) {
			pw_putattributes(draw_win, &text_mask);
			pw_text(draw_win, 200,200,PIX_SRC|PIX_COLOR(TEXT_COLOR),
				big_font, "The qix.");
			Sleep(2);
		    }
		when SHOW_SPARKS :
		    move_sparks();
		    if (time_left == 1) {
			pw_putattributes(draw_win, &text_mask);
			pw_text(draw_win, 15, 110, 
				PIX_SRC|PIX_COLOR(TEXT_COLOR), 
				big_font, "Sparx.");
			pw_text(draw_win,625, 110, 
				PIX_SRC|PIX_COLOR(TEXT_COLOR), 
				big_font, "Sparx.");
			Sleep(2);
		    }
		when SHOW_FUSE :
		    /* after the pw_text, this moves into spiral death trap */
		    switch (time_left) {
			when 230 :
			    drawing = 0;
			    pw_putattributes(draw_win, &text_mask);
			    pw_text(draw_win,
				convert_x(pen_x - 7), convert_y(pen_y + 7),
				PIX_SRC|PIX_COLOR(TEXT_COLOR), 
				big_font, "The fuse.");
			when 80 :
			    pw_putattributes(draw_win, &text_mask);
			    pw_text(draw_win, 265, 445,
				PIX_SRC|PIX_COLOR(TEXT_COLOR), 
				big_font, "The Spiral Death Trap.");
			case 200 : case 240 : case 40 : case 20 :
			    moving = LEFT, drawing = 1;
			when 110 : case  55 : case 30 : moving = RIGHT;
			when 126 : case  65 : case 35 : moving = UP;
			when  95 : case  45 : case 25 : moving = DOWN;
		    }
		    goto movit;
		when SHOW_SPIRAL :
		    if (fuse) { /* when we die, fuse will be NULL */
			time_left = 2;
			goto movit;
		    } else if (region) {
			move_fuse(fuse = NULL);
			rm_cur_line(PIX_SRC|PIX_COLOR(BORDER_COLOR));
		    }
		when SHOW_POINTS : {
		    char buf[5];
		    switch (time_left) {
			when 270 :
			    msg("Use LEFT mouse button for Fast Draw.");
			    drawing = fast = 1, moving = UP;
			    score = 0;
			when 170 :
			    msg("Use MIDDLE mouse button for Slow Draw.");
			    drawing = 1, fast = 0, moving = UP;
			    score = 0;
			when 250 : case 130 : moving = RIGHT;
			when 230 : case  90 : moving = DOWN;
			when 210 : drawing = 0, moving = RIGHT;
			    pw_putattributes(draw_win, &text_mask);
			    (void) sprintf(buf, "%d", score);
			    pw_text(draw_win,
				convert_x(pen_x - 12), convert_y(pen_y - 25),
				PIX_SRC|PIX_COLOR(TEXT_COLOR), big_font, buf);
			when 49 : /* make sure region is closed */
			    msg("Use RIGHT mouse button to STOP movement.");
			    pw_putattributes(draw_win, &text_mask);
			    (void) sprintf(buf, "%d", score);
			    pw_text(draw_win,
				convert_x(pen_x - 12), convert_y(pen_y - 25),
				PIX_SRC|PIX_COLOR(TEXT_COLOR), big_font, buf);
			when 15 : drawing = 0, moving = RIGHT;
		    }
		    goto movit; /* avoid moving qix and sparks */
		}
	    }
	}
	if (play_mode != DEMO)
	    goto done;
    }

    if (move_qix() == -1) {
	change_life(DIE);
	return;
    }

    if (move_sparks() == -1) /* player got hosed */
	return; /* don't restart timer */

movit:
    draw_joystick();
    if (moving == STOP) {
	if (!cur_coord || move_fuse(&fuse) != -1)  /* -1: fuse caught up */
	    start_timer();
	return;
    }
    /* this forces the last fuse to go away */
    (void) move_fuse((struct region *)NULL); /* this can't return -1 */
    if (drawing && !fast && board[pen_x][pen_y] & NEW_LINE
	&& (slow_draw = !slow_draw))
	goto done;

    /*
     * x,y will be the new (proposed) position if the following is true...
     * if not drawing, then check to see if the current cell we're at connects
     * with the proposed new position.  Logic says that it will connect if
     * it "points" that way.. f'rinstance, you can't move left if the current
     * cell doesn't have the "cell-line-left" (CL_LN_LF) attribute. Also,
     * check to see if the current cell has the NEW_LINE attribute. If so,
     * user should be drawing. If he isn't, the fuse starts.
     */
    switch (moving) {
	when LEFT :
	    if (check_painted(x, y, CL_PNT_LEFT) ||
		    !drawing && !(board[x][y] & (CL_LN_LF|NEW_LINE))) {
		if (play_mode == DEMO)
		    time_left = 1;
		goto done;
	    }
	    x--;
	when RIGHT :
	    if (check_painted(x, y, CL_PNT_RIGHT) ||
		    !drawing && !(board[x][y] & (CL_LN_RT|NEW_LINE))) {
		if (play_mode == DEMO)
		    time_left = 1;
		goto done;
	    }
	    x++;
	when UP :
	    if (check_painted(x, y, CL_PNT_TOP) ||
		    !drawing && !(board[x][y] & (CL_LN_UP|NEW_LINE))) {
		if (play_mode == DEMO)
		    time_left = 1;
		goto done;
	    }
	    --y;
	when DOWN :
	    if (check_painted(x, y, CL_PNT_BOT) ||
		    !drawing && !(board[x][y] & (CL_LN_DN|NEW_LINE))) {
		if (play_mode == DEMO)
		    time_left = 1;
		goto done;
	    }
	    ++y;
    }
    old_value = board[pen_x][pen_y];
    new_value = board[x][y];
    /*
     * If drawing, you can't move onto yourself (a "new" line). [start fuse]
     * You can alwasy move onto an old line (completing a region if drawing).
     * If not drawing, you must be on an old line and moving
     * onto another old line. If we're not drawing and *should* be drawing
     * (determined by old_value's NEW_LINE bit set), start a fuse.
     * Also, player can't cheat by fast drawing and suddenly changing to
     * a slow draw just to close a region. Test to see if start_fast is
     * set correctly by testing "region" first.
     */
    if (drawing && (new_value & NEW_LINE) && !(new_value & OLD_LINE) ||
	!drawing && (old_value & NEW_LINE)) {
	if (!fuse) /* if a fuse isn't going, ignite one */
	    fuse = region;
	if (play_mode == DEMO)
	    time_left = 1;
	else
	    moving = STOP;
	goto done;
    }

    /* erase the pen_image, move, reset pen_image, draw line */
    place_pen();

    /* next, determine that if we are drawing, ignore that fact if we
     * are attempting to draw on top of an already drawn line.  If we
     * are creating a new line, then go ahead and create it.
     */
    if (drawing) {
	switch (moving) {
	    when LEFT :
		if (board[pen_x][pen_y] & CL_LN_LF)
		    goto redraw_pen;
		board[pen_x][pen_y] |= CL_LN_LF;
		board[x][y] |= CL_LN_RT;
	    when RIGHT :
		if (board[pen_x][pen_y] & CL_LN_RT)
		    goto redraw_pen;
		board[pen_x][pen_y] |= CL_LN_RT;
		board[x][y] |= CL_LN_LF;
	    when UP :
		if (board[pen_x][pen_y] & CL_LN_UP)
		    goto redraw_pen;
		board[pen_x][pen_y] |= CL_LN_UP;
		board[x][y] |= CL_LN_DN;
	    when DOWN :
		if (board[pen_x][pen_y] & CL_LN_DN)
		    goto redraw_pen;
		board[pen_x][pen_y] |= CL_LN_DN;
		board[x][y] |= CL_LN_UP;
	}
	pw_putattributes(draw_win, &border_mask);
	draw(convert_x(x), convert_y(y),
	     convert_x(pen_x), convert_y(pen_y), 
	     PIX_SRC|PIX_COLOR(BORDER_COLOR));
	if (!region) {
	    saved_edge = old_value;
	    add_to_line(pen_x, pen_y);
	    old_value = (board[pen_x][pen_y] |= NEW_LINE);
	}
	/* if drawing from a newline onto an old line, a region is completed */
	if ((old_value & NEW_LINE) && (new_value & OLD_LINE)) {
	    int new_level = close_region(x, y);
	    if (!new_level)
		update_score();
	    if (new_level || (int)(((double)area_closed/TOTAL_AREA)*100) >= 75){
		if (!new_level) {
		    int percent_closed =
			(int)(((double)area_closed/TOTAL_AREA) * 100);
		    msg("Closed %d%% of the board.", percent_closed);
		    if (percent_closed > 75) {
			score += (percent_closed - 75) * 1000;
			update_score();
			msg("1000 bonus points for each percent over 75%%");
			msg("BONUS: %d", (percent_closed - 75) * 1000);
		    }
		} else
		    level++;
		Sleep(3);
		clear_board(); /* removes msgs also */
		change_life(LIVE);
		stop_timer();
		if (level < 0)
		    level++;
		if (level == 0) {
		    msg("Split the 2 qix to advance score multiplier.");
		    Sleep(2);
		    remove_msgs(0);
		}
		start_timer();
		return;
	    }
	} else if (new_value == 0) {
	    board[x][y] |= NEW_LINE;
	    add_to_line(x, y);
	}
    }
redraw_pen:
    pen_x = x, pen_y = y;
    place_pen(); /* set the new pen image */
done:
    start_timer();
}

draw_joystick()
{
    Pixmap image = moving == LEFT? joystick_left :
		   moving == RIGHT? joystick_right :
		   moving == UP? joystick_up :
		   moving == DOWN? joystick_down :
		   moving == STOP? joystick_stop : ready_icon;
    pw_putattributes(joystick_win, &border_mask);
    pw_rop(joystick_win,
	BOARD_WIDTH_IN_PIXELS/2-32, 2, 64, 64, PIX_SRC|PIX_COLOR(BORDER_COLOR),
	image, 0,0);
    pw_rop(joystick_win, 100,32, 16,23, PIX_SRC|PIX_COLOR(BORDER_COLOR),
	(drawing && fast)? ms_fast_on : ms_fast_off, 0, 0);
    pw_rop(joystick_win, 150,32, 16,23, PIX_SRC|PIX_COLOR(BORDER_COLOR),
	(drawing && !fast)? ms_slow_on : ms_slow_off, 0, 0);
}

/*
 * if "see_it" -- then show the mouse cursor and stop moving mouse to middle
 * of window allowing allow player to grab beer. If "see_it" is
 * false, then the user is ready to move around, so make cursor go away,
 * and force all mouse moves to return to the middle of window.
 */
reset_joystick_win(see_it)
{
#ifndef X11
    Cursor cursor = (Cursor)window_get(Draw, WIN_CURSOR);
#endif /* X11 */

    if (!see_it) {   /* we don't want to see the cursor, so get rid of it */
	/* get the current cursor and make it invisible */
#ifdef X11
	XDefineCursor(dpy, draw_win, None);
#else
	cursor_set(cursor, CURSOR_OP, PIX_DST, 0);
#endif /* X11 */
	moving = STOP;
	draw_joystick();
    } else {
#ifdef X11
	XUndefineCursor(dpy, draw_win);
#endif /* X11 */
	moving = NO_MOVE;
	draw_joystick();
    }
#ifndef X11
    window_set(Joystick, WIN_CURSOR, cursor, 0);
    window_set(Draw, WIN_CURSOR, cursor, 0);
#endif /* X11 */
}