1 /***************************************************************************
2 extras.c - description
3 -------------------
4 begin : Sun Sep 9 2001
5 copyright : (C) 2001 by Michael Speck
6 email : kulkanie@gmx.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "../client/lbreakout.h"
19 #include "levels.h"
20 #include "paddle.h"
21 #include "bricks.h"
22 #include "balls.h"
23 #include "mathfuncs.h"
24 #include "extras.h"
25
26 extern int ball_w, ball_dia;
27 extern Game *cur_game;
28
29 /*
30 ====================================================================
31 Locals
32 ====================================================================
33 */
34
35 /*
36 ====================================================================
37 Public
38 ====================================================================
39 */
40
41 /*
42 ====================================================================
43 Create new extra at position
44 ====================================================================
45 */
extra_create(int type,int x,int y,int dir)46 Extra *extra_create( int type, int x, int y, int dir )
47 {
48 Extra *e = salloc( 1, sizeof( Extra ) );
49 e->type = type;
50 e->offset = type * BRICK_WIDTH;
51 e->x = x; e->y = y;
52 e->dir = dir;
53 e->alpha = 0;
54 return e;
55 }
56
57 /*
58 ====================================================================
59 Use extra when paddle collected it
60 ====================================================================
61 */
extra_use(Paddle * paddle,int extra_type)62 void extra_use( Paddle *paddle, int extra_type )
63 {
64 Ball *b;
65 int i, j;
66 int tm = cur_game->diff->time_mod; /* time modifier */
67
68 printf("%d\n",tm);
69
70 if ( cur_game->diff->allow_maluses ) {
71 while( extra_type == EX_RANDOM )
72 extra_type = rand() % (EX_NUMBER);
73 } else {
74 while ( extra_type == EX_RANDOM || extra_is_malus( extra_type ) )
75 extra_type = rand() % (EX_NUMBER);
76 }
77
78 /* store modification */
79 i = cur_game->paddles[0]==paddle?0:1;
80 if ( cur_game->mod.collected_extra_count[i] < MAX_MODS )
81 cur_game->mod.collected_extras[i][cur_game->mod.collected_extra_count[i]++] =
82 extra_type;
83 /* statistics */
84 paddle->extras_collected++;
85
86 switch (extra_type) {
87 case EX_SCORE200:
88 paddle->score += cur_game->diff->score_mod * 200 / 10;
89 break;
90 case EX_SCORE500:
91 paddle->score += cur_game->diff->score_mod * 500 / 10;
92 break;
93 case EX_SCORE1000:
94 paddle->score += cur_game->diff->score_mod * 1000 / 10;
95 break;
96 case EX_SCORE2000:
97 paddle->score += cur_game->diff->score_mod * 2000 / 10;
98 break;
99 case EX_SCORE5000:
100 paddle->score += cur_game->diff->score_mod * 5000 / 10;
101 break;
102 case EX_SCORE10000:
103 paddle->score += cur_game->diff->score_mod * 10000 / 10;
104 break;
105 case EX_GOLDSHOWER:
106 paddle->extra_time[EX_GOLDSHOWER] += TIME_GOLDSHOWER * tm;
107 paddle->extra_active[EX_GOLDSHOWER] = 1;
108 break;
109 case EX_LIFE:
110 /* adding life is handled by client */
111 break;
112 case EX_SHORTEN:
113 paddle_init_resize( paddle, -1);
114 break;
115 case EX_LENGTHEN:
116 paddle_init_resize( paddle, 1);
117 break;
118 case EX_BALL:
119 b = ball_create(
120 paddle->x + (paddle->w - ball_w) / 2,
121 paddle->y + ((paddle->type == PADDLE_TOP)?paddle->h:-ball_dia) );
122 b->paddle = paddle;
123 ball_set_random_angle( b, cur_game->ball_v );
124 b->get_target = 1;
125 list_add( cur_game->balls, b );
126 break;
127 case EX_WALL:
128 paddle->extra_time[EX_WALL] += TIME_WALL * tm;
129 if ( paddle->extra_active[EX_WALL] ) break;
130 paddle->extra_active[extra_type] = 1;
131 if ( paddle->wall_y == 0 ) {
132 for (i = 1; i < MAP_WIDTH - 1; i++) {
133 cur_game->bricks[i][0].type = MAP_WALL;
134 cur_game->bricks[i][0].id = 0;
135 }
136 }
137 else
138 for (i = 1; i < MAP_WIDTH - 1; i++) {
139 cur_game->bricks[i][MAP_HEIGHT - 1].type = MAP_WALL;
140 cur_game->bricks[i][MAP_HEIGHT - 1].id = 0;
141 }
142 paddle->wall_alpha = 0;
143 balls_check_targets( -1, 0 );
144 break;
145 case EX_METAL:
146 cur_game->extra_time[EX_METAL] += TIME_METAL * tm;
147 cur_game->extra_active[extra_type] = 1;
148 balls_set_type( BALL_METAL );
149 /* other ball extras are disabled */
150 if ( cur_game->extra_active[EX_EXPL_BALL] ) {
151 cur_game->extra_active[EX_EXPL_BALL] = 0;
152 cur_game->extra_time[EX_EXPL_BALL] = 0;
153 }
154 if ( cur_game->extra_active[EX_WEAK_BALL] ) {
155 cur_game->extra_active[EX_WEAK_BALL] = 0;
156 cur_game->extra_time[EX_WEAK_BALL] = 0;
157 }
158 break;
159 case EX_FROZEN:
160 paddle->extra_time[EX_FROZEN] = TIME_FROZEN * tm;
161 paddle->extra_active[extra_type] = 1;
162 paddle_freeze( paddle, 1 );
163 break;
164 case EX_WEAPON:
165 paddle->extra_time[EX_WEAPON] += TIME_WEAPON * tm;
166 paddle->extra_active[extra_type] = 1;
167 weapon_install( paddle, 1 );
168 break;
169 case EX_SLIME:
170 paddle->extra_time[EX_SLIME] += TIME_SLIME * tm;
171 paddle->extra_active[extra_type] = 1;
172 paddle_set_slime( paddle, 1 );
173 break;
174 case EX_FAST:
175 if ( cur_game->extra_active[EX_SLOW] ) {
176 cur_game->extra_time[EX_SLOW] = 0;
177 cur_game->extra_active[EX_SLOW] = 0;
178 }
179 cur_game->extra_time[EX_FAST] += TIME_FAST * tm;
180 cur_game->extra_active[extra_type] = 1;
181 cur_game->ball_v = cur_game->ball_v_max;
182 balls_set_velocity( cur_game->balls, cur_game->ball_v );
183 break;
184 case EX_SLOW:
185 if ( cur_game->extra_active[EX_FAST] ) {
186 cur_game->extra_time[EX_FAST] = 0;
187 cur_game->extra_active[EX_FAST] = 0;
188 }
189 cur_game->extra_time[EX_SLOW] += TIME_SLOW * tm;
190 cur_game->extra_active[extra_type] = 1;
191 cur_game->ball_v = cur_game->ball_v_min;
192 balls_set_velocity( cur_game->balls, cur_game->ball_v );
193 break;
194 case EX_CHAOS:
195 cur_game->extra_time[EX_CHAOS] += TIME_CHAOS * tm;
196 cur_game->extra_active[extra_type] = 1;
197 balls_set_chaos( 1 );
198 break;
199 case EX_DARKNESS:
200 cur_game->extra_time[EX_DARKNESS] += TIME_DARKNESS * tm;
201 cur_game->extra_active[extra_type] = 1;
202 break;
203 case EX_GHOST_PADDLE:
204 paddle->extra_time[EX_GHOST_PADDLE] += TIME_GHOST_PADDLE * tm;
205 paddle->extra_active[extra_type] = 1;
206 paddle_set_invis( paddle, 1 );
207 break;
208 case EX_TIME_ADD:
209 for ( i = 0; i < EX_NUMBER; i++ )
210 if ( cur_game->extra_time[i] )
211 cur_game->extra_time[i] += 7000 * tm;
212 for ( i = 0; i < EX_NUMBER; i++ ) {
213 for ( j = 0; j < cur_game->paddle_count; j++ )
214 if ( cur_game->paddles[j]->extra_time[i] )
215 cur_game->paddles[j]->extra_time[i] += 7000 * tm;
216 }
217 break;
218 case EX_EXPL_BALL:
219 balls_set_type( BALL_EXPL );
220 cur_game->extra_time[EX_EXPL_BALL] += TIME_EXPL_BALL * tm;
221 cur_game->extra_active[extra_type] = 1;
222 /* other ball extras are disabled */
223 if ( cur_game->extra_active[EX_METAL] ) {
224 cur_game->extra_active[EX_METAL] = 0;
225 cur_game->extra_time[EX_METAL] = 0;
226 }
227 if ( cur_game->extra_active[EX_WEAK_BALL] ) {
228 cur_game->extra_active[EX_WEAK_BALL] = 0;
229 cur_game->extra_time[EX_WEAK_BALL] = 0;
230 }
231 break;
232 case EX_WEAK_BALL:
233 balls_set_type( BALL_WEAK );
234 cur_game->extra_time[EX_WEAK_BALL] += TIME_WEAK_BALL * tm;
235 cur_game->extra_active[extra_type] = 1;
236 /* other ball extras are disabled */
237 if ( cur_game->extra_active[EX_METAL] ) {
238 cur_game->extra_active[EX_METAL] = 0;
239 cur_game->extra_time[EX_METAL] = 0;
240 }
241 if ( cur_game->extra_active[EX_EXPL_BALL] ) {
242 cur_game->extra_active[EX_EXPL_BALL] = 0;
243 cur_game->extra_time[EX_EXPL_BALL] = 0;
244 }
245 break;
246 case EX_BONUS_MAGNET:
247 paddle_set_attract( paddle, ATTRACT_BONUS );
248 paddle->extra_time[EX_BONUS_MAGNET] += TIME_BONUS_MAGNET * tm;
249 paddle->extra_active[extra_type] = 1;
250 if ( paddle->extra_active[EX_MALUS_MAGNET] ) {
251 paddle->extra_active[EX_MALUS_MAGNET] = 0;
252 paddle->extra_time[EX_MALUS_MAGNET] = 0;
253 }
254 break;
255 case EX_MALUS_MAGNET:
256 paddle_set_attract( paddle, ATTRACT_MALUS );
257 paddle->extra_time[EX_MALUS_MAGNET] += TIME_MALUS_MAGNET * tm;
258 paddle->extra_active[extra_type] = 1;
259 if ( paddle->extra_active[EX_BONUS_MAGNET] ) {
260 paddle->extra_active[EX_BONUS_MAGNET] = 0;
261 paddle->extra_time[EX_BONUS_MAGNET] = 0;
262 }
263 break;
264 case EX_DISABLE:
265 /* set all active extra times to 1 so they will expire next
266 prog cycle */
267 for ( i = 0; i < EX_NUMBER; i++ )
268 if ( cur_game->extra_time[i] )
269 cur_game->extra_time[i] = 1;
270 for ( i = 0; i < EX_NUMBER; i++ ) {
271 for ( j = 0; j < cur_game->paddle_count; j++ )
272 if ( cur_game->paddles[j]->extra_time[i] )
273 cur_game->paddles[j]->extra_time[i] = 1;
274 }
275 break;
276 default:
277 /* it wasn't used so delete mod */
278 i = cur_game->paddles[0]==paddle?0:1;
279 cur_game->mod.collected_extra_count[i]--;
280 break;
281
282 }
283 }
284 /*
285 ====================================================================
286 Update extras
287 ====================================================================
288 */
extras_update(int ms)289 void extras_update( int ms )
290 {
291 Extra *ex;
292 int i, j;
293 int magnets;
294 Paddle *magnet;
295
296 /* check extra_time of limited extras */
297
298 /* general extras */
299 for ( i = 0; i < EX_NUMBER; i++ )
300 if ( cur_game->extra_time[i] )
301 if ( (cur_game->extra_time[i] -= ms) <= 0 ) {
302 cur_game->extra_time[i] = 0;
303 /* expired */
304 switch ( i ) {
305 case EX_EXPL_BALL:
306 case EX_WEAK_BALL:
307 case EX_METAL:
308 balls_set_type( BALL_NORMAL );
309 break;
310 case EX_SLOW:
311 case EX_FAST:
312 cur_game->ball_v = cur_game->diff->v_start +
313 cur_game->diff->v_add * cur_game->speedup_level;
314 balls_set_velocity( cur_game->balls, cur_game->ball_v );
315 break;
316 case EX_CHAOS:
317 balls_set_chaos( 0 );
318 break;
319 }
320 /* set deactivated */
321 cur_game->extra_active[i] = 0;
322 }
323
324 /* paddlized extras */
325 for ( j = 0; j < cur_game->paddle_count; j++ )
326 for ( i = 0; i < EX_NUMBER; i++ )
327 /* extra_time of wall is updated in wall_update() */
328 if ( cur_game->paddles[j]->extra_time[i] && i != EX_WALL )
329 if ( (cur_game->paddles[j]->extra_time[i] -= ms) <= 0 ) {
330 cur_game->paddles[j]->extra_time[i] = 0;
331 /* expired */
332 switch ( i ) {
333 case EX_SLIME:
334 paddle_set_slime( cur_game->paddles[j], 0 );
335 /* release all balls from paddle */
336 balls_detach_from_paddle( cur_game->paddles[j],
337 ((rand()%2==1)?-1:1) );
338 break;
339 case EX_WEAPON: weapon_install( cur_game->paddles[j], 0 ); break;
340 case EX_FROZEN:
341 paddle_freeze( cur_game->paddles[j], 0 );
342 break;
343 case EX_GHOST_PADDLE:
344 paddle_set_invis( cur_game->paddles[j], 0 );
345 break;
346 case EX_BONUS_MAGNET:
347 case EX_MALUS_MAGNET:
348 paddle_set_attract( cur_game->paddles[j], ATTRACT_NONE );
349 break;
350 }
351 /* set deactivated */
352 cur_game->paddles[j]->extra_active[i] = 0; /* wall is handled in wall_...() */
353 }
354
355 /* move extras and check if paddle was hit */
356 list_reset( cur_game->extras );
357 while ( ( ex = list_next( cur_game->extras ) ) ) {
358 /* if only one paddle has a magnet active all extras will
359 * be attracted by this paddle else the extras 'dir' is used
360 */
361 magnets = 0; magnet = 0;
362 for ( i = 0; i < cur_game->paddle_count; i++ )
363 if ( paddle_check_attract( cur_game->paddles[i], ex->type ) ) {
364 magnets++;
365 magnet = cur_game->paddles[i]; /* last magnet */
366 }
367 if ( magnets != 1 ) {
368 /* either no or more than one magnet so use default */
369 if ( ex->dir > 0 )
370 ex->y += 0.05 * ms;
371 else
372 ex->y -= 0.05 * ms;
373 }
374 else {
375 /* 'magnet' is the paddle that will attract this extra */
376 if ( magnet->type == PADDLE_TOP )
377 ex->y -= 0.05 * ms;
378 else
379 ex->y += 0.05 * ms;
380 if ( ex->x + ( BRICK_WIDTH >> 1 ) < magnet->x + ( magnet->w >> 1 ) ) {
381 ex->x += 0.05 * ms;
382 if ( ex->x + ( BRICK_WIDTH >> 1 ) > magnet->x + ( magnet->w >> 1 ) )
383 ex->x = magnet->x + ( magnet->w >> 1 ) - ( BRICK_WIDTH >> 1 );
384 }
385 else {
386 ex->x -= 0.05 * ms;
387 if ( ex->x + ( BRICK_WIDTH >> 1 ) < magnet->x + ( magnet->w >> 1 ) )
388 ex->x = magnet->x + ( magnet->w >> 1 ) - ( BRICK_WIDTH >> 1 );
389 }
390 }
391 /* if out of screen, kill this extra */
392 if ( ex->y >= 480 || ex->y + BRICK_HEIGHT < 0 ) {
393 list_delete_current( cur_game->extras );
394 continue;
395 }
396 for ( j = 0; j < cur_game->paddle_count; j++ ) {
397 /* contact with paddle core ? */
398 if ( paddle_solid( cur_game->paddles[j] ) )
399 if ( ex->x + BRICK_WIDTH > cur_game->paddles[j]->x )
400 if ( ex->x < cur_game->paddles[j]->x + cur_game->paddles[j]->w - 1 )
401 if ( ex->y + BRICK_HEIGHT > cur_game->paddles[j]->y )
402 if ( ex->y < cur_game->paddles[j]->y + cur_game->paddles[j]->h ) {
403 /* any extra except EX_JOKER is simply used */
404 if ( ex->type != EX_JOKER ) {
405 extra_use( cur_game->paddles[j], ex->type );
406 list_delete_current( cur_game->extras );
407 break;
408 }
409 /* use EX_JOKER and work through all active extras */
410 /* the mod is only stored to play the sound */
411 if ( cur_game->mod.collected_extra_count[j] < MAX_MODS )
412 cur_game->mod.collected_extras[j][cur_game->mod.collected_extra_count[j]++] = EX_JOKER;
413 list_reset( cur_game->extras );
414 while ( ( ex = list_next( cur_game->extras ) ) ) {
415 if ( ex->type != EX_JOKER )
416 if ( ex->type != EX_SHORTEN )
417 if ( ex->type != EX_FROZEN )
418 if ( ex->type != EX_FAST )
419 if ( ex->type != EX_RANDOM )
420 if ( ex->type != EX_DARKNESS )
421 if ( ex->type != EX_GHOST_PADDLE )
422 if ( ex->type != EX_CHAOS )
423 if ( ex->type != EX_DISABLE )
424 if ( ex->type != EX_MALUS_MAGNET )
425 if ( ex->type != EX_WEAK_BALL ) {
426 extra_use( cur_game->paddles[j], ex->type );
427 extra_use( cur_game->paddles[j], ex->type );
428 }
429 list_delete_current( cur_game->extras );
430 }
431 break;
432 }
433 }
434 }
435 }
436
437 /* wall */
walls_update(int ms)438 void walls_update( int ms )
439 {
440 int i, j;
441
442 for ( j = 0; j < cur_game->paddle_count; j++ )
443 if ( cur_game->paddles[j]->extra_active[EX_WALL] ) {
444 if ( cur_game->paddles[j]->extra_time[EX_WALL] > 0 ) {
445 if ( (cur_game->paddles[j]->extra_time[EX_WALL] -= ms) < 0 )
446 cur_game->paddles[j]->extra_time[EX_WALL] = 0;
447 /* still appearing? */
448 if (cur_game->paddles[j]->wall_alpha < 255)
449 if ( (cur_game->paddles[j]->wall_alpha += 0.25 * ms) > 255 )
450 cur_game->paddles[j]->wall_alpha = 255;
451 }
452 else
453 if ( (cur_game->paddles[j]->wall_alpha -= 0.25 * ms) < 0 ) {
454 cur_game->paddles[j]->wall_alpha = 0;
455 cur_game->paddles[j]->extra_active[EX_WALL] = 0;
456 if ( cur_game->paddles[j]->wall_y == 0 )
457 for (i = 1; i < MAP_WIDTH - 1; i++)
458 cur_game->bricks[i][0].type = MAP_EMPTY;
459 else
460 for (i = 1; i < MAP_WIDTH - 1; i++)
461 cur_game->bricks[i][MAP_HEIGHT - 1].type = MAP_EMPTY;
462 balls_check_targets( -1, 0 );
463 }
464 }
465 }
466
extra_is_malus(int type)467 int extra_is_malus( int type )
468 {
469 if ( type == EX_SHORTEN ) return 1;
470 if ( type == EX_FROZEN ) return 1;
471 if ( type == EX_FAST ) return 1;
472 if ( type == EX_DARKNESS ) return 1;
473 if ( type == EX_GHOST_PADDLE ) return 1;
474 if ( type == EX_CHAOS ) return 1;
475 if ( type == EX_DISABLE ) return 1;
476 if ( type == EX_MALUS_MAGNET ) return 1;
477 if ( type == EX_WEAK_BALL ) return 1;
478 return 0;
479 }
480
481