/* * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * * Author & Copyright (C) 2010: Soeren Heisrath (forename@surename.org) * */ #include "ball.h" /* internal functions */ static void ball_spawn (ball_t *in_ball, uint16_t in_x, uint16_t in_y, int16_t in_dir_x, int16_t in_dir_y) { in_ball->x = in_x; in_ball->y = in_y; in_ball->dir_x = in_dir_x; in_ball->dir_y = in_dir_y; } static void ball_die (ball_t *in_b) { in_b->strength--; /* respawn ball with random direction */ if (in_b->strength) { print_ballsleft(in_b); ball_spawn_default (in_b); } } /* modify a vecotor according to given type of bouncing */ static void bounce_rand_vector (ball_t *in_b, uint8_t in_bouncetype) { uint8_t rval = random8(); switch (in_bouncetype) { case BOUNCE_NONE: /* don't touch the vector since nothing changed */ return; case BOUNCE_BRICK: in_b->dir_x ^= (rval & 0x07); in_b->dir_y ^= (rval & 0x07); break; case BOUNCE_REBOUND: /* the rebound is rather percise */ in_b->dir_x ^= (rval & 0x03); in_b->dir_y ^= (rval & 0x03); if (JOYISRIGHT || JOYISLEFT) { /* a moving rebond accelerates the ball 12,5% */ in_b->dir_y += (in_b->dir_y / 8); in_b->dir_x += (in_b->dir_x / 8); } break; default: /* walls */ in_b->dir_x ^= (rval & 0x01); in_b->dir_y ^= (rval & 0x01); } if (!in_b->dir_x) in_b->dir_x = 213; if (!in_b->dir_y) in_b->dir_y = 217; } /* interface functions */ void ball_think (ball_t *b) { int8_t proj_x, proj_y, bounce, tmp; /* projection of the new coordinates */ proj_x = (b->x + (b->dir_x)) / 256; proj_y = (b->y + (b->dir_y)) / 256; /* falling out of the field */ if (proj_y >= NUM_ROWS) ball_die (b); bounce = check_bounce (proj_x, b->y / 256); /* bouncing on bricks needs special handling */ if (bounce & (BOUNCE_BRICK)) bounce |= BOUNCE_X; tmp = check_bounce (b->x / 256, proj_y); if (tmp & (BOUNCE_BRICK)) bounce |= BOUNCE_Y; bounce |= tmp; tmp = check_bounce (proj_x, proj_y); if (tmp & (BOUNCE_BRICK)) bounce |= BOUNCE_X | BOUNCE_Y; bounce |= tmp; bounce_rand_vector (b, bounce); /* bounce in x direction */ if (bounce & BOUNCE_X) { b->dir_x *= -1; /* invert x vector */ } /* bounce in y direction */ if (bounce & BOUNCE_Y) { b->dir_y *= -1; /* invert y vector */ } #if BOUNCE_SLOWDOWN if (bounce & BOUNCE_BRICK) { if (b->dir_y < - BALL_MINSPEED) { b->dir_y += BOUNCE_SLOWDOWN; } else if (b->dir_y > BALL_MINSPEED) { b->dir_y -= BOUNCE_SLOWDOWN; } if (b->dir_x < - BALL_MINSPEED) { b->dir_x += BOUNCE_SLOWDOWN; } else if (b->dir_y > BALL_MINSPEED) { b->dir_x -= BOUNCE_SLOWDOWN; } } #endif if (bounce & BOUNCE_REBOUND) { rebound_reflect(b, proj_x); } if (b->dir_x > BALL_MAXSPEED) b->dir_x = BALL_MAXSPEED; if (b->dir_x < -BALL_MAXSPEED) b->dir_x = -BALL_MAXSPEED; if (b->dir_y > BALL_MAXSPEED) b->dir_y = BALL_MAXSPEED; if (b->dir_y < -BALL_MAXSPEED) b->dir_y = -BALL_MAXSPEED; b->y += b->dir_y; b->x += b->dir_x; } void ball_draw (ball_t *b) { pixel p; p.x = (uint8_t) abs(b->x / 256); p.y = (uint8_t) abs(b->y / 256); setpixel (p, 3); } void ball_spawn_default (ball_t *in_b) { int16_t xdir; xdir = 128 + (random8() & 0x3F); if (random8() & 0x01) xdir *= -1; ball_spawn (in_b, (uint16_t) rebound_getpos() * 256, (NUM_ROWS -2) * 256, xdir, -131); }