home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
x
/
volume19
/
xblockbuster
/
part05
/
balls_pallet.c
Wrap
C/C++ Source or Header
|
1993-04-28
|
16KB
|
606 lines
/*
* File: balls_pallet.c
* Author: Eric Van Gestel
* Updated for X11 by Mark S. Wedel
*
* For: xblockbuster
*
* Implementation:
* Drawing is to be done twice with the same coordinates such that
* the second removes the first while restoring the context.
* The procedure move_balls is called on timeout (xblockbuster.c)
* The procedure draw_pallet is called whenever the pallet changes (mouse
* movement event, button 1 or 2, or hitting a clipper.)
* Auxilary print functions added by MSW to help clean up the code a
* little.
* The auxiliary functions return a boolean value indicating whether
* the hit might have increased the score.
*/
#include "xblockbuster.h"
#include "icons/ball.pr"
static char str[256];
void print_score()
{
sprintf(str, "Score: %d ", score );
XDrawImageString(display, win, gc, OFFSET_SCORE, font_height, str,
strlen(str));
}
void print_balls()
{
sprintf(str, "Balls left: %d ", balls_left);
XDrawImageString(display, win, gc, OFFSET_BALLS, font_height, str,
strlen(str));
}
Pixmap ball_pr;
extern int in_event, do_balls, timer_active;
void ball_init()
{
ball_pr = XCreateBitmapFromData(display, win, ball_bits, ball_width, ball_height);
}
/* Macro to draw a ball */
#define draw_ball( ball ) \
XCopyPlane(display, ball_pr, win, gc_xor, 0, 0, 16, 16, \
(int)( (ball)->x ) - 8, (int)( (ball)->y ) - 8, 1)
/* Procedure to draw the pallet */
void
draw_pallet( )
{
XDrawLine( display, win, gc_xor, pallet_xI - pallet_lengthI + 2, pallet_yI,
pallet_xI + pallet_lengthI - 2, pallet_yI);
XDrawLine( display, win, gc_xor, pallet_xI - pallet_lengthI + 1, pallet_yI + 1,
pallet_xI + pallet_lengthI - 1, pallet_yI + 1);
XDrawLine( display, win, gc_xor, pallet_xI - pallet_lengthI, pallet_yI + 2,
pallet_xI + pallet_lengthI, pallet_yI + 2);
XDrawLine( display, win, gc_xor, pallet_xI - 1, pallet_yI + 3,
pallet_xI - 1, pallet_yI + 6);
XDrawLine( display, win, gc_xor, pallet_xI - 1, pallet_yI + 6,
pallet_xI + 1, pallet_yI + 6);
XDrawLine( display, win, gc_xor, pallet_xI + 1, pallet_yI + 6,
pallet_xI + 1, pallet_yI + 3);
XDrawLine( display, win, gc_xor, 0, mouse_yI - 1, /* <HC> */
10, mouse_yI - 1);
XDrawLine( display, win, gc_xor, 0, mouse_yI,
10, mouse_yI);
XDrawLine( display, win, gc_xor, 0, mouse_yI + 1, /* <HC> */
10, mouse_yI + 1);
XDrawLine( display, win, gc_xor, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI - 1, /* <HC> */
STAGE_WIDTH_IN_PIXELS - 11, mouse_yI - 1);
XDrawLine( display, win, gc_xor, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI,
STAGE_WIDTH_IN_PIXELS - 11, mouse_yI);
XDrawLine( display, win, gc_xor, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI + 1, /* <HC> */
STAGE_WIDTH_IN_PIXELS - 11, mouse_yI + 1);
}
/* Procedure to show the speeds */
#define SX OFFSET_SPEED + 70
void
show_speeds( )
{
int sp;
XDrawImageString(display, win, gc, OFFSET_SPEED, font_height,
"Speed: ",16);
/* scale line */
XDrawLine( display, win, gc, SX, font_height - 1, SX + SPEED_RESOLUTION - 1, font_height - 1);
XDrawLine( display, win, gc, SX, font_height, SX + SPEED_RESOLUTION, font_height);
XDrawLine( display, win, gc, SX, font_height + 1, SX + SPEED_RESOLUTION - 1, font_height + 1);
/* base bar */
XDrawLine( display, win, gc, SX, font_height - 12, SX, font_height + 3);
XDrawLine( display, win, gc, SX + 1, font_height - 12, SX + 1, font_height + 3);
/* launch speed bar */
sp = ( int ) ( launch_speed * SPEED_RESOLUTION_FACTOR );
if ( launch_speed < MAX_SPEED )
XDrawLine( display, win, gc, SX + sp, font_height - 2, SX + sp, font_height + 2);
else
XDrawLine( display, win, gc, SX + sp, font_height - 2, SX + sp, font_height + 2);
/* ball lines */
if ( ball1.quadrant ) {
sp = ( int ) ( ball1.speed * SPEED_RESOLUTION_FACTOR );
XDrawLine( display, win, gc, SX, font_height - 4, SX + sp, font_height - 4);
}
if ( ball2.quadrant ) {
sp = ( int ) ( ball2.speed * SPEED_RESOLUTION_FACTOR );
XDrawLine( display, win, gc, SX, font_height - 7, SX + sp, font_height - 7);
}
if ( ball3.quadrant ) {
sp = ( int ) ( ball3.speed * SPEED_RESOLUTION_FACTOR );
XDrawLine( display, win, gc, SX, font_height - 10, SX + sp, font_height - 10);
}
}
/* auxiliary procedures */
void
new_ball( ball )
register struct Ball *ball;
{
if ( balls_left-- ) {
ball->quadrant = launch_quadrant;
ball->angle = 0.0;
ball->row = launch_row;
ball->col = launch_col;
ball->x = launch_x;
ball->y = launch_y;
ball->speed = launch_speed;
ball->x_speed = launch_speed * ( ( ball->quadrant == NE ) ? M_SQRT2_2
/* NW */ : -M_SQRT2_2 );
ball->y_speed = launch_speed * -M_SQRT2_2;
/* initial ball image */
draw_ball( ball );
/* show balls left */
print_balls();
/* show speeds */
show_speeds( );
} else {
balls_left = 0; /* kludge */
XDrawImageString(display, win, gc, 0, font_height,
"Game Over.",10 );
sleep( 2 );
show_score_board( ); /* BYE !! */
}
}
void
blow_up( row, col )
register int row, col;
{
if ( stage[row][col].code == ' ' )
return; /* nothing there */
if ( IS_HIT_BRICK( stage[row][col].code ) )
nbricks--;
stage[row][col].code = 'R';
draw_brick( row, col );
}
int /* boolean */
hit_brick( hit, ball )
register int hit; /* enumeration { HORIZONTAL, VERTICAL } */
register struct Ball *ball;
{
register struct Brick *brick = &stage[ball->row][ball->col];
register int busted = FALSE;
register int redraw = FALSE;
register int score_hit = FALSE;
char str[80];
/* has the ball left the stage vertically ? */
if ( ball->row < 0 || ball->row > MAX_ROW ) {
ball->quadrant = NO_BALL; /* so much for this ball */
return ( score_hit );
}
/* check for looping */
switch ( brick->code ) {
case ' ': /* no hit */
break;
case '#':
case '/':
case '\\':
case '^':
case '0':
case 'A':
case 'R':
case 'S':
case 'U': /* because it may undo another one */
case 'W':
case '%':
if ( !( ++loop_nhits % LOOP_MAX ) )
ball->x -=
ball->x_speed * ( double ) ( loop_nhits / LOOP_MAX ) + 1;
/* horizontal shift, trying to get out of a bounce loop */
/* negative to try to avoid leaving the stage */
break;
default: /* non-solid brick */
loop_nhits = 0;
}
/* advance score taking special action if needed */
switch ( brick->code ) {
case ' ': /* clear space */
/* has the ball left the stage horizontally ? */
if ( ball->col <= 0 || ball->col >= MAX_COL ) {
ball->quadrant = NO_BALL; /* so much for this ball */
}
return ( score_hit ); /* no hit */
case '#': /* solid wall */
case '/': /* launchpad NE */
case '\\': /* launchpad NW */
case '^': /* emitter */
break;
case '0': /* solid brick */
score += score_incr;
score_hit = TRUE;
break;
case 'A': /* absorber */
ball->x += ( double ) ( emit_col - ball->col ) * 64;
ball->y += ( double ) ( emit_row - ball->row ) * 16;
break;
case 'C': /* clipper */
if ( ++( brick->nhits ) == 2 ) {
draw_pallet();
pallet_lengthI -= pallet_lengthI / 5;
if ( pallet_lengthI < MIN_PALLET_LENGTH )
pallet_lengthI = MIN_PALLET_LENGTH;
pallet_length = ( double ) pallet_lengthI;
busted = TRUE;
draw_pallet();
}
break;
case 'D': /* double */
if ( ++( brick->nhits ) == 2 ) {
score_incr *= 2;
busted = TRUE;
sprintf(str,"Bonus x%d",score_incr);
XDrawImageString(display, win, gc,
OFFSET_SCORE, font_height*2, str,
strlen(str));
}
break;
case 'E': /* extra ball */
if ( ++( brick->nhits ) == 2 ) {
balls_left++;
print_balls();
busted = TRUE;
}
break;
case 'G': /* gap */
if ( ++( brick->nhits ) == 2 ) {
ball->quadrant = NO_BALL; /* so much for this ball */
busted = TRUE;
}
break;
case 'H': /* halt */
if ( ++( brick->nhits ) == 3 )
busted = TRUE;
{
double pause = 0.1 * ( double ) ( 10 - brick->nhits );
ball->speed *= pause;
ball->x_speed *= pause;
ball->y_speed *= pause;
}
/* approximative; will be corrected on next pallet deflection */
show_speeds( );
break;
case 'I': /* invisible brick */
score += score_incr;
brick->code = '1';
nbricks++;
score_hit = redraw = TRUE;
break;
case 'L': /* launch ball */
if ( ++( brick->nhits ) == 2 ) {
balls_left++; /* kludge to avoid consuming a ball */
if ( !ball1.quadrant )
new_ball( &ball1 );
else if ( !ball2.quadrant )
new_ball( &ball2 );
else if ( !ball3.quadrant )
new_ball( &ball3 );
else
print_balls();
show_speeds( );
busted = TRUE;
}
break;
case 'M': /* mine */
if ( ++( brick->nhits ) == 3 ) {
blow_up( ball->row - 1, ball->col - 1 );
blow_up( ball->row - 1, ball->col );
blow_up( ball->row - 1, ball->col + 1 );
blow_up( ball->row, ball->col - 1 );
blow_up( ball->row, ball->col + 1 );
blow_up( ball->row + 1, ball->col - 1 );
blow_up( ball->row + 1, ball->col );
blow_up( ball->row + 1, ball->col + 1 );
busted = TRUE;
}
break;
case 'P': /* pause */
if ( ++( brick->nhits ) == 8 ) {
launch_speed -= ( launch_speed - INIT_SPEED ) * 0.3;
busted = TRUE;
}
show_speeds( );
break;
case 'R': /* refractor */
ball->angle = -( ball->angle );
{
register int sign = ( ball->x_speed * ball->y_speed ) < 0;
register double tmp = ball->x_speed;
ball->x_speed = sign ? -( ball->y_speed ) : ball->y_speed;
ball->y_speed = sign ? -tmp : tmp;
/*
* note no check for NEAR_HORIZONTAL and none needed
* since,
*/
/*
* if it gets too horizontal, it probably will hit it
* again.
*/
}
return ( FALSE ); /* no deflection */
case 'S': /* speeder */
if ( ball->speed < SPEED_LIMIT ) {
ball->speed += SPEED_INCR;
ball->x_speed += ( ball->x_speed < 0 ) ? -SPEED_INCR_2
: SPEED_INCR_2;
ball->y_speed += ( ball->y_speed < 0 ) ? -SPEED_INCR_2
: SPEED_INCR_2;
/*
* approximative; will be corrected on next pallet
* deflection
*/
show_speeds( );
} else
pallet_modif++;
break;
case 'T': /* triple */
if ( ++( brick->nhits ) == 3 ) {
score_incr *= 3;
busted = TRUE;
sprintf(str,"Bonus x%d",score_incr);
XDrawImageString(display, win, gc,
OFFSET_SCORE, font_height*2, str,
strlen(str));
}
break;
case 'U': /* undo */ ;
/* effective only after something has been busted */
if ( last_busted_brick ) {
last_busted_brick->code = last_busted_code;
last_busted_brick->nhits = 0;
if ( IS_HIT_BRICK( last_busted_code ) )
nbricks++;
draw_brick( last_busted_row, last_busted_col );
busted = TRUE;
}
break;
case 'W': /* open window */ ;
brick->code = '%';
/* redraw = TRUE */ draw_brick( ball->row, ball->col );
return ( score_hit ); /* no deflection */
case '%': /* closed window */ ;
brick->code = 'W';
redraw = TRUE;
break;
case 'X': /* expander */
if ( ++( brick->nhits ) == 4 ) {
pallet_modif -= 2 * PALLET_INCR;
busted = TRUE;
}
break;
default:
if ( brick->code >= '1' && brick->code <= '9' ) {
/* hit bricks */
score += ++( brick->nhits ) * score_incr;
score_hit = TRUE;
if ( brick->nhits == brick->code - '0' )
busted = TRUE;
else
redraw = TRUE;
} else { /* 'a' .. 'e' & 'j' */
/* bonus= bricks */
if ( ++( brick->nhits ) > brick->code - 'a' + 1 ) {
score += ( brick->code - 'a' + 1 ) * 10 * score_incr;
score_hit = busted = TRUE;
}
}
}
if ( busted ) {
last_busted_brick = brick;
last_busted_code = brick->code;
last_busted_row = ball->row;
last_busted_col = ball->col;
if ( IS_HIT_BRICK( brick->code ) )
nbricks--;
brick->code = ' ';
redraw = TRUE;
}
/* redraw brick (never on the sides) */
if ( redraw ) {
if ( pallet_row == ball->row )
draw_pallet( ); /* avoid shadow */
draw_brick( ball->row, ball->col );
if ( pallet_row == ball->row )
draw_pallet( ); /* restore */
}
/* deflection */
if ( ball->col <= 0 || ball->col >= MAX_COL ) {
/*
* kludge to avoid tunnelling out through the side (or
* corner)
*/
if ( ( ball->col <= 0 &&
( ball->quadrant == NW || ball->quadrant == SW ) ) ||
( ball->col >= MAX_COL &&
( ball->quadrant == NE || ball->quadrant == SE ) ) )
brick_deflection( VERTICAL, ball );
if ( ( ball->row == 0 &&
( ball->quadrant == NE || ball->quadrant == NW ) ) ||
( ball->row == MAX_ROW &&
( ball->quadrant == SE || ball->quadrant == SW ) ) )
brick_deflection( HORIZONTAL, ball );
} else
brick_deflection( hit, ball );
return ( score_hit );
}
int /* boolean */
move_ball( ball )
register struct Ball *ball;
{
register int tmp; /* tmp row or col designation */
register int hit = FALSE; /* enumeration { FALSE, HORIZONTAL,
* VERTICAL } */
register int score_hit = FALSE; /* boolean */
/* erase ball image */
draw_ball( ball );
/* move ball */
ball->x += ball->x_speed;
ball->y += ball->y_speed;
/* might it have hit a brick ? */
if ( ( tmp = X_COL( ball->x ) ) != ball->col ) {
ball->col = tmp;
hit = VERTICAL;
}
if ( ( tmp = Y_ROW( ball->y ) ) != ball->row ) {
ball->row = tmp;
hit = HORIZONTAL; /* HORIZONTAL takes precedence over
* VERTICAL */
}
if ( hit )
score_hit = hit_brick( hit, ball );
if ( !ball->quadrant ) {
/* so much for this ball */
show_speeds( );
return ( score_hit );
}
/* might it have hit the pallet ? */
if ( ball->y >= pallet_y - 0.1 && /* round of protection */
ball->y <= pallet_y + ball->y_speed &&
ball->x >= pallet_x - pallet_length &&
ball->x <= pallet_x + pallet_length ) {
loop_nhits = 0;
pallet_deflection( ball );
}
/* redraw ball image */
draw_ball( ball );
return ( score_hit );
}
void check_ball(ball, old_pallet_y)
register struct Ball *ball;
double old_pallet_y;
{
if ( ball->y >= pallet_y - 0.1 && /* round of protection */
ball->y <= old_pallet_y + ball->y_speed &&
ball->x >= pallet_x - pallet_length &&
ball->x <= pallet_x + pallet_length ) {
loop_nhits = 0;
pallet_deflection( ball );
}
}
void
check_deflections(old_pallet_y )
double old_pallet_y;
{
if (ball1.quadrant) check_ball(&ball1,old_pallet_y);
if (ball2.quadrant) check_ball(&ball3,old_pallet_y);
if (ball3.quadrant) check_ball(&ball3,old_pallet_y);
}
void draw_balls()
{
if ( ball1.quadrant ) draw_ball(&ball1);
if ( ball2.quadrant ) draw_ball(&ball2);
if ( ball3.quadrant ) draw_ball(&ball3);
}
/*** on timeout event ***/
void move_balls( )
{
register int score_hit1 = FALSE, score_hit2 = FALSE, score_hit3 = FALSE;
/* start new ball if none left */
if ( !ball1.quadrant && !ball2.quadrant && !ball3.quadrant ) {
new_ball( &ball1 );
}
/* move balls */
if ( ball1.quadrant )
score_hit1 = move_ball( &ball1 );
if ( ball2.quadrant )
score_hit2 = move_ball( &ball2 );
if ( ball3.quadrant )
score_hit3 = move_ball( &ball3 );
/* start new stage if no more bricks to bust */
if ( nbricks <= 0 ) {
/* add stage bonus */
score += 100;
XFillRectangle( display,win, gc_erase,
0, 0, STAGE_WIDTH_IN_PIXELS - 1, MSG_HEIGHT);
XDrawImageString(display, win, gc,
0,font_height, " Stage bonus: 100",17);
/* erase ball images */
if ( ball1.quadrant ) {
ball1.quadrant = NO_BALL;
balls_left++; /* kludge to avoid consuming the ball */
draw_ball( &ball1 );
}
if ( ball2.quadrant ) {
ball2.quadrant = NO_BALL;
balls_left++; /* kludge to avoid consuming the ball */
draw_ball( &ball2 );
}
if ( ball3.quadrant ) {
ball3.quadrant = NO_BALL;
balls_left++; /* kludge to avoid consuming the ball */
draw_ball( &ball3 );
}
/* update score */
print_score();
timer_active=0;
/* off we go again */
new_stage( );
} else {
/* update score */
if ( score_hit1 || score_hit2 || score_hit3 )
print_score();
if (!ball1.quadrant && !ball2.quadrant && !ball3.quadrant) {
timer_active=0;
XFlush(display);
if (balls_left==0) {
print_balls();
show_score_board( ); /* BYE !! */
}
}
}
}