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

⟦984bd820d⟧ TextFile

    Length: 17782 (0x4576)
    Types: TextFile
    Names: »joystick.c«

Derivation

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

TextFile

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

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

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

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

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

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

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

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

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

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

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

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

/*
 * 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, data)
register Canvas canvas;
register Event *event;
{
    register int ID = event->ie_code;
    static start_fast;

    if (play_mode != REAL_PLAY && ID != ' ' && ID != MS_RIGHT)
	return;

    if ((ID == LOC_MOVE) && moving != NO_MOVE) {
	register int delta_x, delta_y;
	if (event_x(event) <= 0)
	    event_set_x(event, 1);
	if (event_y(event) <= 0)
	    event_set_y(event, 1);
	delta_x = event_x(event) - MID_X;
	delta_y = event_y(event) - 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;
	} else if (event_shift_is_down(event))
	    fast = drawing = 1;
	else if (event_meta_is_down(event))
	    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' : case KEY_RIGHT(10) :
	    moving = LEFT;
	when 'l' : case 'L' : case KEY_RIGHT(12) :
	    moving = RIGHT;
	when 'j' : case 'J' : case KEY_RIGHT(14) :
	    moving = DOWN;
	when 'k' : case 'K' : case KEY_RIGHT(8) :
	    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 &&
	(event_x(event) != MID_X || event_y(event) != MID_Y))
	window_set(canvas, WIN_MOUSE_XY, MID_X, MID_Y, 0);
}

/*
 * 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;

    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;
			update_score();
			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);
			    pw_text(draw_win,
				convert_x(pen_x - 12), convert_y(pen_y - 25),
				PIX_SRC|PIX_COLOR(TEXT_COLOR), 
				big_font, sprintf(buf, "%d", score));
			when 49 : /* make sure region is closed */
			    msg("Use RIGHT mouse button to STOP movement.");
			    pw_putattributes(draw_win, &text_mask);
			    pw_text(draw_win,
				convert_x(pen_x - 12), convert_y(pen_y - 25),
				PIX_SRC|PIX_COLOR(TEXT_COLOR), 
				big_font, sprintf(buf, "%d", score));
			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()
{
    Pixrect *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)
{
    static int oldop;

    Cursor cursor = (Cursor)window_get(Draw, WIN_CURSOR);

    if (!see_it) {   /* we don't want to see the cursor, so get rid of it */
	/* get the current cursor and make it invisible */
	oldop = (int)cursor_get(cursor, CURSOR_OP);
	cursor_set(cursor, CURSOR_OP, PIX_DST, 0);
	moving = STOP;
	draw_joystick();
    } else {
	/* cursor_set(cursor, CURSOR_OP, oldop, 0); */
	moving = NO_MOVE;
	draw_joystick();
    }
    window_set(Joystick, WIN_CURSOR, cursor, 0);
    window_set(Draw, WIN_CURSOR, cursor, 0);
}