/***************************************************************************
extras.c - description
-------------------
begin : Sun Sep 9 2001
copyright : (C) 2001 by Michael Speck
email : kulkanie@gmx.net
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "../client/lbreakout.h"
#include "levels.h"
#include "paddle.h"
#include "bricks.h"
#include "balls.h"
#include "mathfuncs.h"
#include "extras.h"
extern int ball_w, ball_dia;
extern Game *cur_game;
/*
====================================================================
Locals
====================================================================
*/
/*
====================================================================
Public
====================================================================
*/
/*
====================================================================
Create new extra at position
====================================================================
*/
Extra *extra_create( int type, int x, int y, int dir )
{
Extra *e = salloc( 1, sizeof( Extra ) );
e->type = type;
e->offset = type * BRICK_WIDTH;
e->x = x; e->y = y;
e->dir = dir;
e->alpha = 0;
return e;
}
/*
====================================================================
Use extra when paddle collected it
====================================================================
*/
void extra_use( Paddle *paddle, int extra_type )
{
Ball *b;
int i, j;
int tm = cur_game->diff->time_mod; /* time modifier */
printf("%d\n",tm);
if ( cur_game->diff->allow_maluses ) {
while( extra_type == EX_RANDOM )
extra_type = rand() % (EX_NUMBER);
} else {
while ( extra_type == EX_RANDOM || extra_is_malus( extra_type ) )
extra_type = rand() % (EX_NUMBER);
}
/* store modification */
i = cur_game->paddles[0]==paddle?0:1;
if ( cur_game->mod.collected_extra_count[i] < MAX_MODS )
cur_game->mod.collected_extras[i][cur_game->mod.collected_extra_count[i]++] =
extra_type;
/* statistics */
paddle->extras_collected++;
switch (extra_type) {
case EX_SCORE200:
paddle->score += cur_game->diff->score_mod * 200 / 10;
break;
case EX_SCORE500:
paddle->score += cur_game->diff->score_mod * 500 / 10;
break;
case EX_SCORE1000:
paddle->score += cur_game->diff->score_mod * 1000 / 10;
break;
case EX_SCORE2000:
paddle->score += cur_game->diff->score_mod * 2000 / 10;
break;
case EX_SCORE5000:
paddle->score += cur_game->diff->score_mod * 5000 / 10;
break;
case EX_SCORE10000:
paddle->score += cur_game->diff->score_mod * 10000 / 10;
break;
case EX_GOLDSHOWER:
paddle->extra_time[EX_GOLDSHOWER] += TIME_GOLDSHOWER * tm;
paddle->extra_active[EX_GOLDSHOWER] = 1;
break;
case EX_LIFE:
/* adding life is handled by client */
break;
case EX_SHORTEN:
paddle_init_resize( paddle, -1);
break;
case EX_LENGTHEN:
paddle_init_resize( paddle, 1);
break;
case EX_BALL:
b = ball_create(
paddle->x + (paddle->w - ball_w) / 2,
paddle->y + ((paddle->type == PADDLE_TOP)?paddle->h:-ball_dia) );
b->paddle = paddle;
ball_set_random_angle( b, cur_game->ball_v );
b->get_target = 1;
list_add( cur_game->balls, b );
break;
case EX_WALL:
paddle->extra_time[EX_WALL] += TIME_WALL * tm;
if ( paddle->extra_active[EX_WALL] ) break;
paddle->extra_active[extra_type] = 1;
if ( paddle->wall_y == 0 ) {
for (i = 1; i < MAP_WIDTH - 1; i++) {
cur_game->bricks[i][0].type = MAP_WALL;
cur_game->bricks[i][0].id = 0;
}
}
else
for (i = 1; i < MAP_WIDTH - 1; i++) {
cur_game->bricks[i][MAP_HEIGHT - 1].type = MAP_WALL;
cur_game->bricks[i][MAP_HEIGHT - 1].id = 0;
}
paddle->wall_alpha = 0;
balls_check_targets( -1, 0 );
break;
case EX_METAL:
cur_game->extra_time[EX_METAL] += TIME_METAL * tm;
cur_game->extra_active[extra_type] = 1;
balls_set_type( BALL_METAL );
/* other ball extras are disabled */
if ( cur_game->extra_active[EX_EXPL_BALL] ) {
cur_game->extra_active[EX_EXPL_BALL] = 0;
cur_game->extra_time[EX_EXPL_BALL] = 0;
}
if ( cur_game->extra_active[EX_WEAK_BALL] ) {
cur_game->extra_active[EX_WEAK_BALL] = 0;
cur_game->extra_time[EX_WEAK_BALL] = 0;
}
break;
case EX_FROZEN:
paddle->extra_time[EX_FROZEN] = TIME_FROZEN * tm;
paddle->extra_active[extra_type] = 1;
paddle_freeze( paddle, 1 );
break;
case EX_WEAPON:
paddle->extra_time[EX_WEAPON] += TIME_WEAPON * tm;
paddle->extra_active[extra_type] = 1;
weapon_install( paddle, 1 );
break;
case EX_SLIME:
paddle->extra_time[EX_SLIME] += TIME_SLIME * tm;
paddle->extra_active[extra_type] = 1;
paddle_set_slime( paddle, 1 );
break;
case EX_FAST:
if ( cur_game->extra_active[EX_SLOW] ) {
cur_game->extra_time[EX_SLOW] = 0;
cur_game->extra_active[EX_SLOW] = 0;
}
cur_game->extra_time[EX_FAST] += TIME_FAST * tm;
cur_game->extra_active[extra_type] = 1;
cur_game->ball_v = cur_game->ball_v_max;
balls_set_velocity( cur_game->balls, cur_game->ball_v );
break;
case EX_SLOW:
if ( cur_game->extra_active[EX_FAST] ) {
cur_game->extra_time[EX_FAST] = 0;
cur_game->extra_active[EX_FAST] = 0;
}
cur_game->extra_time[EX_SLOW] += TIME_SLOW * tm;
cur_game->extra_active[extra_type] = 1;
cur_game->ball_v = cur_game->ball_v_min;
balls_set_velocity( cur_game->balls, cur_game->ball_v );
break;
case EX_CHAOS:
cur_game->extra_time[EX_CHAOS] += TIME_CHAOS * tm;
cur_game->extra_active[extra_type] = 1;
balls_set_chaos( 1 );
break;
case EX_DARKNESS:
cur_game->extra_time[EX_DARKNESS] += TIME_DARKNESS * tm;
cur_game->extra_active[extra_type] = 1;
break;
case EX_GHOST_PADDLE:
paddle->extra_time[EX_GHOST_PADDLE] += TIME_GHOST_PADDLE * tm;
paddle->extra_active[extra_type] = 1;
paddle_set_invis( paddle, 1 );
break;
case EX_TIME_ADD:
for ( i = 0; i < EX_NUMBER; i++ )
if ( cur_game->extra_time[i] )
cur_game->extra_time[i] += 7000 * tm;
for ( i = 0; i < EX_NUMBER; i++ ) {
for ( j = 0; j < cur_game->paddle_count; j++ )
if ( cur_game->paddles[j]->extra_time[i] )
cur_game->paddles[j]->extra_time[i] += 7000 * tm;
}
break;
case EX_EXPL_BALL:
balls_set_type( BALL_EXPL );
cur_game->extra_time[EX_EXPL_BALL] += TIME_EXPL_BALL * tm;
cur_game->extra_active[extra_type] = 1;
/* other ball extras are disabled */
if ( cur_game->extra_active[EX_METAL] ) {
cur_game->extra_active[EX_METAL] = 0;
cur_game->extra_time[EX_METAL] = 0;
}
if ( cur_game->extra_active[EX_WEAK_BALL] ) {
cur_game->extra_active[EX_WEAK_BALL] = 0;
cur_game->extra_time[EX_WEAK_BALL] = 0;
}
break;
case EX_WEAK_BALL:
balls_set_type( BALL_WEAK );
cur_game->extra_time[EX_WEAK_BALL] += TIME_WEAK_BALL * tm;
cur_game->extra_active[extra_type] = 1;
/* other ball extras are disabled */
if ( cur_game->extra_active[EX_METAL] ) {
cur_game->extra_active[EX_METAL] = 0;
cur_game->extra_time[EX_METAL] = 0;
}
if ( cur_game->extra_active[EX_EXPL_BALL] ) {
cur_game->extra_active[EX_EXPL_BALL] = 0;
cur_game->extra_time[EX_EXPL_BALL] = 0;
}
break;
case EX_BONUS_MAGNET:
paddle_set_attract( paddle, ATTRACT_BONUS );
paddle->extra_time[EX_BONUS_MAGNET] += TIME_BONUS_MAGNET * tm;
paddle->extra_active[extra_type] = 1;
if ( paddle->extra_active[EX_MALUS_MAGNET] ) {
paddle->extra_active[EX_MALUS_MAGNET] = 0;
paddle->extra_time[EX_MALUS_MAGNET] = 0;
}
break;
case EX_MALUS_MAGNET:
paddle_set_attract( paddle, ATTRACT_MALUS );
paddle->extra_time[EX_MALUS_MAGNET] += TIME_MALUS_MAGNET * tm;
paddle->extra_active[extra_type] = 1;
if ( paddle->extra_active[EX_BONUS_MAGNET] ) {
paddle->extra_active[EX_BONUS_MAGNET] = 0;
paddle->extra_time[EX_BONUS_MAGNET] = 0;
}
break;
case EX_DISABLE:
/* set all active extra times to 1 so they will expire next
prog cycle */
for ( i = 0; i < EX_NUMBER; i++ )
if ( cur_game->extra_time[i] )
cur_game->extra_time[i] = 1;
for ( i = 0; i < EX_NUMBER; i++ ) {
for ( j = 0; j < cur_game->paddle_count; j++ )
if ( cur_game->paddles[j]->extra_time[i] )
cur_game->paddles[j]->extra_time[i] = 1;
}
break;
default:
/* it wasn't used so delete mod */
i = cur_game->paddles[0]==paddle?0:1;
cur_game->mod.collected_extra_count[i]--;
break;
}
}
/*
====================================================================
Update extras
====================================================================
*/
void extras_update( int ms )
{
Extra *ex;
int i, j;
int magnets;
Paddle *magnet;
/* check extra_time of limited extras */
/* general extras */
for ( i = 0; i < EX_NUMBER; i++ )
if ( cur_game->extra_time[i] )
if ( (cur_game->extra_time[i] -= ms) <= 0 ) {
cur_game->extra_time[i] = 0;
/* expired */
switch ( i ) {
case EX_EXPL_BALL:
case EX_WEAK_BALL:
case EX_METAL:
balls_set_type( BALL_NORMAL );
break;
case EX_SLOW:
case EX_FAST:
cur_game->ball_v = cur_game->diff->v_start +
cur_game->diff->v_add * cur_game->speedup_level;
balls_set_velocity( cur_game->balls, cur_game->ball_v );
break;
case EX_CHAOS:
balls_set_chaos( 0 );
break;
}
/* set deactivated */
cur_game->extra_active[i] = 0;
}
/* paddlized extras */
for ( j = 0; j < cur_game->paddle_count; j++ )
for ( i = 0; i < EX_NUMBER; i++ )
/* extra_time of wall is updated in wall_update() */
if ( cur_game->paddles[j]->extra_time[i] && i != EX_WALL )
if ( (cur_game->paddles[j]->extra_time[i] -= ms) <= 0 ) {
cur_game->paddles[j]->extra_time[i] = 0;
/* expired */
switch ( i ) {
case EX_SLIME:
paddle_set_slime( cur_game->paddles[j], 0 );
/* release all balls from paddle */
balls_detach_from_paddle( cur_game->paddles[j],
((rand()%2==1)?-1:1) );
break;
case EX_WEAPON: weapon_install( cur_game->paddles[j], 0 ); break;
case EX_FROZEN:
paddle_freeze( cur_game->paddles[j], 0 );
break;
case EX_GHOST_PADDLE:
paddle_set_invis( cur_game->paddles[j], 0 );
break;
case EX_BONUS_MAGNET:
case EX_MALUS_MAGNET:
paddle_set_attract( cur_game->paddles[j], ATTRACT_NONE );
break;
}
/* set deactivated */
cur_game->paddles[j]->extra_active[i] = 0; /* wall is handled in wall_...() */
}
/* move extras and check if paddle was hit */
list_reset( cur_game->extras );
while ( ( ex = list_next( cur_game->extras ) ) ) {
/* if only one paddle has a magnet active all extras will
* be attracted by this paddle else the extras 'dir' is used
*/
magnets = 0; magnet = 0;
for ( i = 0; i < cur_game->paddle_count; i++ )
if ( paddle_check_attract( cur_game->paddles[i], ex->type ) ) {
magnets++;
magnet = cur_game->paddles[i]; /* last magnet */
}
if ( magnets != 1 ) {
/* either no or more than one magnet so use default */
if ( ex->dir > 0 )
ex->y += 0.05 * ms;
else
ex->y -= 0.05 * ms;
}
else {
/* 'magnet' is the paddle that will attract this extra */
if ( magnet->type == PADDLE_TOP )
ex->y -= 0.05 * ms;
else
ex->y += 0.05 * ms;
if ( ex->x + ( BRICK_WIDTH >> 1 ) < magnet->x + ( magnet->w >> 1 ) ) {
ex->x += 0.05 * ms;
if ( ex->x + ( BRICK_WIDTH >> 1 ) > magnet->x + ( magnet->w >> 1 ) )
ex->x = magnet->x + ( magnet->w >> 1 ) - ( BRICK_WIDTH >> 1 );
}
else {
ex->x -= 0.05 * ms;
if ( ex->x + ( BRICK_WIDTH >> 1 ) < magnet->x + ( magnet->w >> 1 ) )
ex->x = magnet->x + ( magnet->w >> 1 ) - ( BRICK_WIDTH >> 1 );
}
}
/* if out of screen, kill this extra */
if ( ex->y >= 480 || ex->y + BRICK_HEIGHT < 0 ) {
list_delete_current( cur_game->extras );
continue;
}
for ( j = 0; j < cur_game->paddle_count; j++ ) {
/* contact with paddle core ? */
if ( paddle_solid( cur_game->paddles[j] ) )
if ( ex->x + BRICK_WIDTH > cur_game->paddles[j]->x )
if ( ex->x < cur_game->paddles[j]->x + cur_game->paddles[j]->w - 1 )
if ( ex->y + BRICK_HEIGHT > cur_game->paddles[j]->y )
if ( ex->y < cur_game->paddles[j]->y + cur_game->paddles[j]->h ) {
/* any extra except EX_JOKER is simply used */
if ( ex->type != EX_JOKER ) {
extra_use( cur_game->paddles[j], ex->type );
list_delete_current( cur_game->extras );
break;
}
/* use EX_JOKER and work through all active extras */
/* the mod is only stored to play the sound */
if ( cur_game->mod.collected_extra_count[j] < MAX_MODS )
cur_game->mod.collected_extras[j][cur_game->mod.collected_extra_count[j]++] = EX_JOKER;
list_reset( cur_game->extras );
while ( ( ex = list_next( cur_game->extras ) ) ) {
if ( ex->type != EX_JOKER )
if ( ex->type != EX_SHORTEN )
if ( ex->type != EX_FROZEN )
if ( ex->type != EX_FAST )
if ( ex->type != EX_RANDOM )
if ( ex->type != EX_DARKNESS )
if ( ex->type != EX_GHOST_PADDLE )
if ( ex->type != EX_CHAOS )
if ( ex->type != EX_DISABLE )
if ( ex->type != EX_MALUS_MAGNET )
if ( ex->type != EX_WEAK_BALL ) {
extra_use( cur_game->paddles[j], ex->type );
extra_use( cur_game->paddles[j], ex->type );
}
list_delete_current( cur_game->extras );
}
break;
}
}
}
}
/* wall */
void walls_update( int ms )
{
int i, j;
for ( j = 0; j < cur_game->paddle_count; j++ )
if ( cur_game->paddles[j]->extra_active[EX_WALL] ) {
if ( cur_game->paddles[j]->extra_time[EX_WALL] > 0 ) {
if ( (cur_game->paddles[j]->extra_time[EX_WALL] -= ms) < 0 )
cur_game->paddles[j]->extra_time[EX_WALL] = 0;
/* still appearing? */
if (cur_game->paddles[j]->wall_alpha < 255)
if ( (cur_game->paddles[j]->wall_alpha += 0.25 * ms) > 255 )
cur_game->paddles[j]->wall_alpha = 255;
}
else
if ( (cur_game->paddles[j]->wall_alpha -= 0.25 * ms) < 0 ) {
cur_game->paddles[j]->wall_alpha = 0;
cur_game->paddles[j]->extra_active[EX_WALL] = 0;
if ( cur_game->paddles[j]->wall_y == 0 )
for (i = 1; i < MAP_WIDTH - 1; i++)
cur_game->bricks[i][0].type = MAP_EMPTY;
else
for (i = 1; i < MAP_WIDTH - 1; i++)
cur_game->bricks[i][MAP_HEIGHT - 1].type = MAP_EMPTY;
balls_check_targets( -1, 0 );
}
}
}
int extra_is_malus( int type )
{
if ( type == EX_SHORTEN ) return 1;
if ( type == EX_FROZEN ) return 1;
if ( type == EX_FAST ) return 1;
if ( type == EX_DARKNESS ) return 1;
if ( type == EX_GHOST_PADDLE ) return 1;
if ( type == EX_CHAOS ) return 1;
if ( type == EX_DISABLE ) return 1;
if ( type == EX_MALUS_MAGNET ) return 1;
if ( type == EX_WEAK_BALL ) return 1;
return 0;
}