1 /***************************************************************************
5 copyright : (C) 2001 by Michael Speck
6 email : kulkanie@gmx.net
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
18 #include "lbreakout.h"
19 #include "../game/game.h"
21 #include "shrapnells.h"
26 extern Player
*cur_player
;
27 extern SDL_Surface
*stk_display
;
28 extern SDL_Rect stk_drect
;
29 extern SDL_Surface
*offscreen
;
30 extern SDL_Surface
*bkgnd
; /* background + frame */
31 extern SDL_Surface
*offscreen_backup
;
32 extern int ball_w
, ball_dia
;
33 extern SDL_Surface
*brick_pic
;
34 extern Brick bricks
[MAP_WIDTH
][MAP_HEIGHT
];
35 extern SDL_Surface
*extra_pic
; /* graphics */
36 extern SDL_Surface
*extra_shadow
;
37 extern SDL_Surface
*paddle_pic
, *weapon_pic
;
38 extern SDL_Surface
*ball_pic
;
39 extern SDL_Surface
*shot_pic
;
40 extern StkFont
*display_font
;
41 extern SDL_Surface
*wall_pic
;
42 extern int shadow_size
;
44 extern StkSound
*wav_score
, *wav_metal
, *wav_std
, *wav_wall
, *wav_joker
;
45 extern StkSound
*wav_goldshower
, *wav_life_up
;
46 extern StkSound
*wav_speedup
, *wav_speeddown
;
47 extern StkSound
*wav_chaos
, *wav_darkness
, *wav_ghost
;
48 extern StkSound
*wav_timeadd
, *wav_expl_ball
, *wav_weak_ball
;
49 extern StkSound
*wav_bonus_magnet
, *wav_malus_magnet
, *wav_disable
;
50 extern StkSound
*wav_attach
; /* handled by balls.c */
51 extern StkSound
*wav_expand
, *wav_shrink
, *wav_frozen
;
53 extern Game
*game
; /* client game context */
55 extern int ball_pic_x_offset
;
58 ====================================================================
60 ====================================================================
64 ====================================================================
66 ====================================================================
69 /* Play sounds and handle graphical effects. */
70 void client_handle_collected_extra( Paddle
*paddle
, int extra_type
)
74 int px
= paddle
->x
+(paddle
->w
>>1);
81 stk_sound_play_x( px
, wav_joker
);
83 list_reset( game
->extras
);
84 while ( ( ex
= list_next( game
->extras
) ) ) {
85 stk_display_store_rect( &ex
->update_rect
);
86 list_delete_current( game
->extras
);
96 stk_sound_play_x( px
, wav_score
);
100 paddle
->extra_time
[EX_GOLDSHOWER
] += TIME_GOLDSHOWER
;
101 paddle
->extra_active
[EX_GOLDSHOWER
] = 1;
103 stk_sound_play_x( px
, wav_goldshower
);
107 if ( game
->game_type
== GT_LOCAL
) {
108 if ( paddle
->player
->lives
< game
->diff
->max_lives
) {
109 paddle
->player
->lives
++;
116 stk_sound_play_x( px
, wav_shrink
);
118 paddle_init_resize( paddle
, -1);
122 stk_sound_play_x( px
, wav_expand
);
124 paddle_init_resize( paddle
, 1);
128 stk_sound_play_x( px
, wav_std
);
132 paddle
->extra_time
[EX_WALL
] += TIME_WALL
;
133 if ( paddle
->extra_active
[EX_WALL
] ) {
135 stk_sound_play_x( px
, wav_std
);
139 paddle
->extra_active
[extra_type
] = 1;
140 paddle
->wall_alpha
= 0;
142 stk_sound_play_x( px
, wav_wall
);
146 game
->extra_time
[EX_METAL
] += TIME_METAL
;
147 game
->extra_active
[extra_type
] = 1;
148 ball_pic_x_offset
= ball_w
;
150 stk_sound_play_x( px
, wav_metal
);
152 /* other ball extras are disabled */
153 if ( game
->extra_active
[EX_EXPL_BALL
] ) {
154 game
->extra_active
[EX_EXPL_BALL
] = 0;
155 game
->extra_time
[EX_EXPL_BALL
] = 0;
157 if ( game
->extra_active
[EX_WEAK_BALL
] ) {
158 game
->extra_active
[EX_WEAK_BALL
] = 0;
159 game
->extra_time
[EX_WEAK_BALL
] = 0;
163 paddle
->extra_time
[EX_FROZEN
] = TIME_FROZEN
;
164 paddle
->extra_active
[extra_type
] = 1;
165 paddle
->pic_y_offset
= paddle_ch
*2;
166 paddle
->frozen
= 1; /* the server sided paddle is blocked
167 so does the same with the local copy */
169 stk_sound_play_x( px
, wav_frozen
);
173 paddle
->extra_time
[EX_WEAPON
] += TIME_WEAPON
;
174 paddle
->extra_active
[extra_type
] = 1;
175 weapon_install( paddle
, 1 );
177 stk_sound_play_x( px
, wav_std
);
181 paddle
->extra_time
[EX_SLIME
] += TIME_SLIME
;
182 paddle
->extra_active
[extra_type
] = 1;
183 if ( !paddle
->frozen
)
184 paddle
->pic_y_offset
= paddle_ch
;
186 stk_sound_play_x( px
, wav_attach
);
191 stk_sound_play_x( px
, wav_speedup
);
193 if ( game
->extra_active
[EX_SLOW
] ) {
194 game
->extra_time
[EX_SLOW
] = 0;
195 game
->extra_active
[EX_SLOW
] = 0;
197 game
->extra_time
[EX_FAST
] += TIME_FAST
;
198 game
->extra_active
[extra_type
] = 1;
202 stk_sound_play_x( px
, wav_speeddown
);
204 if ( game
->extra_active
[EX_FAST
] ) {
205 game
->extra_time
[EX_FAST
] = 0;
206 game
->extra_active
[EX_FAST
] = 0;
208 game
->extra_time
[EX_SLOW
] += TIME_SLOW
;
209 game
->extra_active
[extra_type
] = 1;
213 stk_sound_play_x( px
, wav_chaos
);
215 game
->extra_time
[EX_CHAOS
] += TIME_CHAOS
;
216 game
->extra_active
[extra_type
] = 1;
220 stk_sound_play_x( px
, wav_darkness
);
222 game
->extra_time
[EX_DARKNESS
] += TIME_DARKNESS
;
223 if ( game
->extra_active
[EX_DARKNESS
] ) break;
224 /* backup offscreen and turn it black */
225 stk_surface_fill( offscreen
, 0,0,-1,-1, 0x0 );
226 stk_surface_fill( stk_display
, 0,0,-1,-1, 0x0 );
227 stk_display_store_rect( 0 );
228 /* set alpha keys to 128 */
229 SDL_SetAlpha( paddle_pic
, SDL_SRCALPHA
, 128 );
230 SDL_SetAlpha( weapon_pic
, SDL_SRCALPHA
, 128 );
231 SDL_SetAlpha( extra_pic
, SDL_SRCALPHA
, 128 );
232 SDL_SetAlpha( ball_pic
, SDL_SRCALPHA
, 128 );
233 SDL_SetAlpha( shot_pic
, SDL_SRCALPHA
, 128 );
234 SDL_SetAlpha( display_font
->surface
, SDL_SRCALPHA
, 128 );
235 /* use dark explosions */
237 game
->extra_active
[extra_type
] = 1;
239 case EX_GHOST_PADDLE
:
241 stk_sound_play_x( px
, wav_ghost
);
243 paddle
->extra_time
[EX_GHOST_PADDLE
] += TIME_GHOST_PADDLE
;
244 paddle
->extra_active
[extra_type
] = 1;
245 paddle_set_invis( paddle
, 1 );
249 stk_sound_play_x( px
, wav_timeadd
);
251 for ( i
= 0; i
< EX_NUMBER
; i
++ )
252 if ( game
->extra_time
[i
] )
253 game
->extra_time
[i
] += 7000;
254 for ( i
= 0; i
< EX_NUMBER
; i
++ ) {
255 for ( j
= 0; j
< game
->paddle_count
; j
++ )
256 if ( game
->paddles
[j
]->extra_time
[i
] )
257 game
->paddles
[j
]->extra_time
[i
] += 7000;
262 stk_sound_play_x( px
, wav_expl_ball
);
264 ball_pic_x_offset
= ball_w
*2;
265 game
->extra_time
[EX_EXPL_BALL
] += TIME_EXPL_BALL
;
266 game
->extra_active
[extra_type
] = 1;
267 /* other ball extras are disabled */
268 if ( game
->extra_active
[EX_METAL
] ) {
269 game
->extra_active
[EX_METAL
] = 0;
270 game
->extra_time
[EX_METAL
] = 0;
272 if ( game
->extra_active
[EX_WEAK_BALL
] ) {
273 game
->extra_active
[EX_WEAK_BALL
] = 0;
274 game
->extra_time
[EX_WEAK_BALL
] = 0;
279 stk_sound_play_x( px
, wav_weak_ball
);
281 ball_pic_x_offset
= ball_w
*3;
282 game
->extra_time
[EX_WEAK_BALL
] += TIME_WEAK_BALL
;
283 game
->extra_active
[extra_type
] = 1;
284 /* other ball extras are disabled */
285 if ( game
->extra_active
[EX_METAL
] ) {
286 game
->extra_active
[EX_METAL
] = 0;
287 game
->extra_time
[EX_METAL
] = 0;
289 if ( game
->extra_active
[EX_EXPL_BALL
] ) {
290 game
->extra_active
[EX_EXPL_BALL
] = 0;
291 game
->extra_time
[EX_EXPL_BALL
] = 0;
294 case EX_BONUS_MAGNET
:
296 stk_sound_play_x( px
, wav_bonus_magnet
);
298 paddle_set_attract( paddle
, ATTRACT_BONUS
);
299 paddle
->extra_time
[EX_BONUS_MAGNET
] += TIME_BONUS_MAGNET
;
300 paddle
->extra_active
[extra_type
] = 1;
301 if ( paddle
->extra_active
[EX_MALUS_MAGNET
] ) {
302 paddle
->extra_active
[EX_MALUS_MAGNET
] = 0;
303 paddle
->extra_time
[EX_MALUS_MAGNET
] = 0;
306 case EX_MALUS_MAGNET
:
308 stk_sound_play_x( px
, wav_malus_magnet
);
310 paddle_set_attract( paddle
, ATTRACT_MALUS
);
311 paddle
->extra_time
[EX_MALUS_MAGNET
] += TIME_MALUS_MAGNET
;
312 paddle
->extra_active
[extra_type
] = 1;
313 if ( paddle
->extra_active
[EX_BONUS_MAGNET
] ) {
314 paddle
->extra_active
[EX_BONUS_MAGNET
] = 0;
315 paddle
->extra_time
[EX_BONUS_MAGNET
] = 0;
320 stk_sound_play_x( px
, wav_disable
);
322 /* set all active extra times to 1 so they will expire next
324 for ( i
= 0; i
< EX_NUMBER
; i
++ )
325 if ( game
->extra_time
[i
] )
326 game
->extra_time
[i
] = 1;
327 for ( i
= 0; i
< EX_NUMBER
; i
++ ) {
328 for ( j
= 0; j
< game
->paddle_count
; j
++ )
329 if ( game
->paddles
[j
]->extra_time
[i
] )
330 game
->paddles
[j
]->extra_time
[i
] = 1;
336 ====================================================================
338 ====================================================================
342 ListEntry
*entry
= game
->extras
->head
->next
;
344 while ( entry
!= game
->extras
->tail
) {
347 stk_surface_blit( offscreen
,
348 (int)ex
->x
, (int)ex
->y
,
349 BRICK_WIDTH
+ shadow_size
, BRICK_HEIGHT
+ shadow_size
,
350 stk_display
, (int)ex
->x
, (int)ex
->y
);
351 ex
->update_rect
= stk_drect
;
352 stk_display_store_rect( &ex
->update_rect
);
355 void extras_show_shadow()
357 ListEntry
*entry
= game
->extras
->head
->next
;
359 while ( entry
!= game
->extras
->tail
) {
361 stk_surface_clip( stk_display
, 0,0,
362 stk_display
->w
- BRICK_WIDTH
, stk_display
->h
);
363 stk_surface_alpha_blit(
364 extra_shadow
, extra
->type
* BRICK_WIDTH
, 0,
365 BRICK_WIDTH
, BRICK_HEIGHT
,
366 stk_display
, (int)extra
->x
+ shadow_size
, (int)extra
->y
+ shadow_size
,
367 ((int)extra
->alpha
)>>1 );
368 stk_surface_clip( stk_display
, 0,0,-1,-1 );
374 ListEntry
*entry
= game
->extras
->head
->next
;
377 while ( entry
!= game
->extras
->tail
) {
380 x
= (int)ex
->x
; y
= (int)ex
->y
;
381 stk_surface_alpha_blit( extra_pic
, ex
->offset
, 0,
382 BRICK_WIDTH
, BRICK_HEIGHT
, stk_display
, x
, y
, ex
->alpha
);
384 if ( x
< ex
->update_rect
.x
) {
385 /* movement to left */
386 ex
->update_rect
.w
+= ex
->update_rect
.x
- x
;
387 ex
->update_rect
.x
= x
;
390 /* movement to right */
391 ex
->update_rect
.w
+= x
- ex
->update_rect
.x
;
392 if ( ex
->dir
== -1 ) {
394 ex
->update_rect
.h
+= ex
->update_rect
.y
- y
;
395 ex
->update_rect
.y
= y
;
396 if ( ex
->update_rect
.y
< 0 ) {
397 ex
->update_rect
.h
+= ex
->update_rect
.y
;
398 ex
->update_rect
.y
= 0;
403 ex
->update_rect
.h
+= y
- ex
->update_rect
.y
;
404 if ( ex
->update_rect
.y
+ ex
->update_rect
.h
>= stk_display
->h
)
405 ex
->update_rect
.h
= stk_display
->h
- ex
->update_rect
.y
;
407 stk_display_store_rect( &ex
->update_rect
);
409 ex
->update_rect
.x
= x
;
410 ex
->update_rect
.y
= y
;
411 ex
->update_rect
.w
= BRICK_WIDTH
+ shadow_size
;
412 ex
->update_rect
.h
= BRICK_HEIGHT
+ shadow_size
;
413 stk_display_store_rect( &ex
->update_rect
);
416 void extras_alphashow( int alpha
)
418 ListEntry
*entry
= game
->extras
->head
->next
;
421 while ( entry
!= game
->extras
->tail
) {
425 stk_surface_alpha_blit( extra_pic
, ex
->type
* BRICK_WIDTH
, 0,
426 BRICK_WIDTH
, BRICK_HEIGHT
, stk_display
, x
, y
, alpha
);
427 stk_display_store_rect( &ex
->update_rect
);
432 /* move the extras as in extras_update but do not collect them */
433 void client_extras_update( int ms
)
440 /* check extra_time of limited extras */
442 for ( i
= 0; i
< EX_NUMBER
; i
++ )
443 if ( game
->extra_time
[i
] ) {
444 if ( (game
->extra_time
[i
] -= ms
) <= 0 ) {
445 game
->extra_time
[i
] = 0;
451 ball_pic_x_offset
= 0;
454 /* restore offscreen */
455 stk_surface_blit( bkgnd
, 0,0,-1,-1, offscreen
, 0,0 );
457 if ( game
->game_type
== GT_LOCAL
)
458 frame_draw_lives( cur_player
->lives
,
459 game
->diff
->max_lives
);
462 offscreen
, 0,0,-1,-1,
464 stk_display_store_rect( 0 );
465 /* set alpha keys to OPAQUE */
466 SDL_SetAlpha( paddle_pic
, 0,0 );
467 SDL_SetAlpha( extra_pic
, 0,0 );
468 SDL_SetAlpha( ball_pic
, 0,0 );
469 SDL_SetAlpha( shot_pic
, 0,0 );
470 SDL_SetAlpha( display_font
->surface
, 0,0 );
471 /* use bright explosions */
475 /* set deactivated */
476 game
->extra_active
[i
] = 0;
479 /* paddlized extras */
480 for ( j
= 0; j
< game
->paddle_count
; j
++ )
481 for ( i
= 0; i
< EX_NUMBER
; i
++ )
482 /* extra_time of wall is updated in client_walls_update() */
483 if ( game
->paddles
[j
]->extra_time
[i
] && i
!= EX_WALL
)
484 if ( (game
->paddles
[j
]->extra_time
[i
] -= ms
) <= 0 ) {
485 game
->paddles
[j
]->extra_time
[i
] = 0;
490 if ( game
->paddles
[j
]->extra_time
[EX_SLIME
] > 0 )
491 game
->paddles
[j
]->pic_y_offset
= paddle_ch
;
493 game
->paddles
[j
]->pic_y_offset
= 0;
494 game
->paddles
[j
]->frozen
= 0;
497 weapon_install( game
->paddles
[j
], 0 );
499 case EX_GHOST_PADDLE
:
500 paddle_set_invis( game
->paddles
[j
], 0 );
502 case EX_BONUS_MAGNET
:
503 case EX_MALUS_MAGNET
:
504 paddle_set_attract( game
->paddles
[j
], ATTRACT_NONE
);
507 /* set deactivated */
508 game
->paddles
[j
]->extra_active
[i
] = 0; /* wall is handled in wall_...() */
511 /* move extras and check if paddle was hit */
512 list_reset( game
->extras
);
513 while ( ( ex
= list_next( game
->extras
) ) ) {
514 /* if only one paddle has a magnet active all extras will
515 * be attracted by this paddle else the extras 'dir' is used
517 magnets
= 0; magnet
= 0;
518 for ( i
= 0; i
< game
->paddle_count
; i
++ )
519 if ( paddle_check_attract( game
->paddles
[i
], ex
->type
) ) {
521 magnet
= game
->paddles
[i
]; /* last magnet */
523 if ( magnets
!= 1 ) {
524 /* either no or more than one magnet so use default */
531 /* 'magnet' is the paddle that will attract this extra */
532 if ( magnet
->type
== PADDLE_TOP
)
536 if ( ex
->x
+ ( BRICK_WIDTH
>> 1 ) < magnet
->x
+ ( magnet
->w
>> 1 ) ) {
538 if ( ex
->x
+ ( BRICK_WIDTH
>> 1 ) > magnet
->x
+ ( magnet
->w
>> 1 ) )
539 ex
->x
= magnet
->x
+ ( magnet
->w
>> 1 ) - ( BRICK_WIDTH
>> 1 );
543 if ( ex
->x
+ ( BRICK_WIDTH
>> 1 ) < magnet
->x
+ ( magnet
->w
>> 1 ) )
544 ex
->x
= magnet
->x
+ ( magnet
->w
>> 1 ) - ( BRICK_WIDTH
>> 1 );
547 if ( !game
->extra_active
[EX_DARKNESS
] ) {
548 if ( ex
->alpha
< 255 ) {
549 ex
->alpha
+= 0.25 * ms
;
555 if ( ex
->alpha
< 128 ) {
556 ex
->alpha
+= 0.25 * ms
;
561 /* if out of screen forget this extra */
562 if ( ex
->y
>= stk_display
->h
|| ex
->y
+ BRICK_HEIGHT
< 0 ) {
563 stk_display_store_rect( &ex
->update_rect
);
564 list_delete_current( game
->extras
);
567 for ( j
= 0; j
< game
->paddle_count
; j
++ ) {
568 /* contact with paddle core ? */
569 if ( paddle_solid( game
->paddles
[j
] ) )
570 if ( ex
->x
+ BRICK_WIDTH
> game
->paddles
[j
]->x
)
571 if ( ex
->x
< game
->paddles
[j
]->x
+ game
->paddles
[j
]->w
- 1 )
572 if ( ex
->y
+ BRICK_HEIGHT
> game
->paddles
[j
]->y
)
573 if ( ex
->y
< game
->paddles
[j
]->y
+ game
->paddles
[j
]->h
) {
574 /* remove extra but don't handle it */
575 stk_display_store_rect( &ex
->update_rect
);
576 list_delete_current( game
->extras
);
586 for ( j
= 0; j
< game
->paddle_count
; j
++ )
587 if ( game
->paddles
[j
]->extra_active
[EX_WALL
] ) {
588 stk_surface_blit( offscreen
, BRICK_WIDTH
, game
->paddles
[j
]->wall_y
,
589 wall_pic
->w
, wall_pic
->h
,
590 stk_display
, BRICK_WIDTH
, game
->paddles
[j
]->wall_y
);
591 stk_display_store_drect();
597 for ( j
= 0; j
< game
->paddle_count
; j
++ )
598 if ( game
->paddles
[j
]->extra_active
[EX_WALL
] )
599 stk_surface_alpha_blit( wall_pic
, 0,0,
600 wall_pic
->w
, wall_pic
->h
,
601 stk_display
, BRICK_WIDTH
, game
->paddles
[j
]->wall_y
,
602 (int)game
->paddles
[j
]->wall_alpha
);
604 void walls_alphashow( int alpha
)
607 for ( j
= 0; j
< game
->paddle_count
; j
++ )
608 if ( game
->paddles
[j
]->extra_active
[EX_WALL
] )
609 stk_surface_alpha_blit( wall_pic
, 0,0,
610 wall_pic
->w
, wall_pic
->h
,
611 stk_display
, BRICK_WIDTH
, game
->paddles
[j
]->wall_y
,
614 void client_walls_update( int ms
)
618 for ( j
= 0; j
< game
->paddle_count
; j
++ )
619 if ( game
->paddles
[j
]->extra_active
[EX_WALL
] ) {
620 if ( game
->paddles
[j
]->extra_time
[EX_WALL
] > 0 ) {
621 if ( (game
->paddles
[j
]->extra_time
[EX_WALL
] -= ms
) < 0 )
622 game
->paddles
[j
]->extra_time
[EX_WALL
] = 0;
623 /* still appearing? */
624 if (game
->paddles
[j
]->wall_alpha
< 255)
625 if ( (game
->paddles
[j
]->wall_alpha
+= 0.25 * ms
) > 255 )
626 game
->paddles
[j
]->wall_alpha
= 255;
629 if ( (game
->paddles
[j
]->wall_alpha
-= 0.25 * ms
) < 0 ) {
630 game
->paddles
[j
]->wall_alpha
= 0;
631 game
->paddles
[j
]->extra_active
[EX_WALL
] = 0;