home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume11
/
blockbuster
/
part01
/
balls_pallet.c
next >
Wrap
C/C++ Source or Header
|
1990-08-10
|
16KB
|
603 lines
/*
* File: balls_pallet.c
* Author: Eric Van Gestel
*
* For: blockbuster
*
* Implementation:
* Drawing is to be done twice with the same coordinates such that
* the second removes the first while restoring the context.
* The procedures move_pallet and move_balls are to be called on
* mouse and timeout events respectively.
* The auxiliary functions return a boolean value indicating whether
* the hit might have increased the score.
*/
/*** WORKAROUND for a Horizontal Crosshair ***/
#include "blockbuster.h"
#include "bricks.h"
short ball_image[] = {
#include "icons/ball.pr"
};
mpr_static( ball_pr, 16, 16, 1, ball_image );
/* Macro to draw a ball */
#define draw_ball( ball ) \
/* struct Ball *ball */ \
pw_rop( stage_win, (int)( (ball)->x ) - 8, (int)( (ball)->y ) - 8, 16, 16, \
PIX_XOR, &ball_pr, 0, 0 )
/* Procedure to draw the pallet */
void
draw_pallet( )
{
pw_vector( stage_win, pallet_xI - pallet_lengthI + 2, pallet_yI,
pallet_xI + pallet_lengthI - 2, pallet_yI,
PIX_XOR, 1 );
pw_vector( stage_win, pallet_xI - pallet_lengthI + 1, pallet_yI + 1,
pallet_xI + pallet_lengthI - 1, pallet_yI + 1,
PIX_XOR, 1 );
pw_vector( stage_win, pallet_xI - pallet_lengthI, pallet_yI + 2,
pallet_xI + pallet_lengthI, pallet_yI + 2,
PIX_XOR, 1 );
pw_vector( stage_win, pallet_xI - 1, pallet_yI + 3,
pallet_xI - 1, pallet_yI + 6,
PIX_XOR, 1 );
pw_vector( stage_win, pallet_xI - 1, pallet_yI + 6,
pallet_xI + 1, pallet_yI + 6,
PIX_XOR, 1 );
pw_vector( stage_win, pallet_xI + 1, pallet_yI + 6,
pallet_xI + 1, pallet_yI + 3,
PIX_XOR, 1 );
pw_vector( stage_win, 0, mouse_yI - 1, /* <HC> */
10, mouse_yI - 1, /* <HC> */
PIX_XOR, 1 );/* <HC> */
pw_vector( stage_win, 0, mouse_yI,
10, mouse_yI,/* <HC> */
PIX_XOR, 1 );/* <HC> */
pw_vector( stage_win, 0, mouse_yI + 1, /* <HC> */
10, mouse_yI + 1, /* <HC> */
PIX_XOR, 1 );/* <HC> */
pw_vector( stage_win, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI - 1, /* <HC> */
STAGE_WIDTH_IN_PIXELS - 11, mouse_yI - 1, /* <HC> */
PIX_XOR, 1 );/* <HC> */
pw_vector( stage_win, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI,
STAGE_WIDTH_IN_PIXELS - 11, mouse_yI, /* <HC> */
PIX_XOR, 1 );/* <HC> */
pw_vector( stage_win, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI + 1, /* <HC> */
STAGE_WIDTH_IN_PIXELS - 11, mouse_yI + 1, /* <HC> */
PIX_XOR, 1 );/* <HC> */
}
/* Procedure to show the speeds */
#define SX OFFSET_SPEED + 70
#define SY FONT_HEIGHT
void
show_speeds( )
{
int sp;
msg0( OFFSET_SPEED, "Speed:%10c", ' ' );
/* scale line */
pw_vector( msg_win, SX, SY - 1, SX + SPEED_RESOLUTION - 1, SY - 1, PIX_SRC, 1 );
pw_vector( msg_win, SX, SY, SX + SPEED_RESOLUTION, SY, PIX_SRC, 1 );
pw_vector( msg_win, SX, SY + 1, SX + SPEED_RESOLUTION - 1, SY + 1, PIX_SRC, 1 );
/* base bar */
pw_vector( msg_win, SX, SY - 12, SX, SY + 3, PIX_SRC, 1 );
pw_vector( msg_win, SX + 1, SY - 12, SX + 1, SY + 3, PIX_SRC, 1 );
/* launch speed bar */
sp = ( int ) ( launch_speed * SPEED_RESOLUTION_FACTOR );
if ( launch_speed < MAX_SPEED )
pw_vector( msg_win, SX + sp, SY - 2, SX + sp, SY + 2, PIX_XOR, 1 );
else
pw_vector( msg_win, SX + sp, SY - 2, SX + sp, SY + 2, PIX_SRC, 1 );
/* ball lines */
if ( ball1.quadrant ) {
sp = ( int ) ( ball1.speed * SPEED_RESOLUTION_FACTOR );
pw_vector( msg_win, SX, SY - 4, SX + sp, SY - 4, PIX_SRC, 1 );
}
if ( ball2.quadrant ) {
sp = ( int ) ( ball2.speed * SPEED_RESOLUTION_FACTOR );
pw_vector( msg_win, SX, SY - 7, SX + sp, SY - 7, PIX_SRC, 1 );
}
if ( ball3.quadrant ) {
sp = ( int ) ( ball3.speed * SPEED_RESOLUTION_FACTOR );
pw_vector( msg_win, SX, SY - 10, SX + sp, SY - 10, PIX_SRC, 1 );
}
}
/* 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 */
msg0( OFFSET_BALLS, "Balls left: %d ", balls_left );
/* show speeds */
show_speeds( );
} else {
balls_left = 0; /* kludge */
msg( 0, "Game Over." );
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;
/* 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 ) {
pallet_lengthI -= pallet_lengthI / 5;
if ( pallet_lengthI < MIN_PALLET_LENGTH )
pallet_lengthI = MIN_PALLET_LENGTH;
pallet_length = ( double ) pallet_lengthI;
busted = TRUE;
}
break;
case 'D': /* double */
if ( ++( brick->nhits ) == 2 ) {
score_incr *= 2;
busted = TRUE;
}
break;
case 'E': /* extra ball */
if ( ++( brick->nhits ) == 2 ) {
balls_left++;
msg0( OFFSET_BALLS, "Balls left: %d ", balls_left );
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
msg0( OFFSET_BALLS, "Balls left: %d ", balls_left );
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;
}
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; /* 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 );
}
/*** on timeout event ***/
Notify_value
move_balls( frm, which_itimer )
Frame frm; /* ignored */
int which_itimer; /* enumeration { ITIMER_REAL } **
* ignored */
{
register int score_hit1 = FALSE, score_hit2 = FALSE, score_hit3 = FALSE;
/* halt cycle */
stop_timer( );
/* 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;
msg( 0, "Stage bonus: 100" );
/* erase pallet image */
draw_pallet( );
/* 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 */
msg0( OFFSET_SCORE, "Score: %d ", score );
/* off we go again */
new_stage( );
} else {
/* update score */
if ( score_hit1 || score_hit2 || score_hit3 )
msg0( OFFSET_SCORE, "Score: %d ", score );
/* next cycle */
start_timer( );
}
return ( NOTIFY_DONE );
}
/*** on mouse events ***/
int
move_pallet( cvs, event, arg )
Canvas cvs; /* ignored */
Event *event;
caddr_t arg; /* ignored */
{
register int tmp;
/* erase pallet image */
draw_pallet( );
switch ( event_id( event ) ) {
case MS_LEFT:
if ( pallet_yI > PALLET_MIN_Y ) {
pallet_y = ( double ) ( pallet_yI -= 16 );
pallet_row--;
}
break;
case MS_MIDDLE:
pallet_y = ( double ) ( pallet_yI = PALLET_MAX_Y + 4 );
pallet_row = MAX_ROW - 1;
break;
case MS_RIGHT:
/* clear msg */
for ( tmp = 0; tmp < MSG_HEIGHT; tmp++ )
pw_vector( msg_win, 0, tmp, STAGE_WIDTH_IN_PIXELS - 1, tmp,
PIX_CLR, 1 );
/* redo all messages */
msg1( OFFSET_SPEED, stage_name );
msg0( OFFSET_BALLS, "Balls left: %d ", balls_left );
msg0( OFFSET_SCORE, "Score: %d ", score );
show_speeds( );
/* lets go ! */
move_balls( ); /* starts the timer */
break;
case KEY_RIGHT( 1 ):
if ( !ball1.quadrant && !ball2.quadrant && !ball3.quadrant ) {
msg0( OFFSET_BALLS, "Saving...%46c", ' ' );
save( ); /* BYE !! */
} else
msg0( OFFSET_BALLS, "Not saved...%43c", ' ' );
break;
default: /* LOC_MOVE, LOC_STILL */
/* move pallet */
pallet_x = ( double ) ( pallet_xI = event_x( event ) );
mouse_yI = event_y( event ); /* <HC> */
}
/* redraw pallet image */
draw_pallet( );
}