|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T j
Length: 21409 (0x53a1) Types: TextFile Names: »joystick.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/X/Qix/joystick.c«
#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 */ }