prevents stucking in some situations, when Tux is ducked.
[supertux.git] / src / player.c
1 //
2 // C Implementation: player/tux
3 //
4 // Description:
5 //
6 //
7 // Author: Tobias Glaesser <tobi.web@gmx.de> & Bill Kendrick, (C) 2004
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12
13 #include "gameloop.h"
14 #include "globals.h"
15 #include "player.h"
16 #include "defines.h"
17 #include "scene.h"
18 #include "screen.h"
19
20 texture_type tux_life,
21 tux_right[3],  tux_left[3],
22 bigtux_right[3],  bigtux_left[3],
23 bigtux_right_jump,  bigtux_left_jump,
24 ducktux_right,  ducktux_left,
25 skidtux_right,  skidtux_left,
26 firetux_right[3],  firetux_left[3],
27 bigfiretux_right[3],  bigfiretux_left[3],
28 bigfiretux_right_jump,  bigfiretux_left_jump,
29 duckfiretux_right,  duckfiretux_left,
30 skidfiretux_right,  skidfiretux_left,
31 cape_right[2],  cape_left[2],
32 bigcape_right[2],  bigcape_left[2];
33
34 void player_input_init(player_input_type* pplayer_input)
35 {
36   pplayer_input->down = UP;
37   pplayer_input->fire = UP;
38   pplayer_input->left = UP;
39   pplayer_input->old_fire = UP;
40   pplayer_input->right = UP;
41   pplayer_input->up = UP;
42 }
43
44 void player_init(player_type* pplayer)
45 {
46   pplayer->base.width = 32;
47   pplayer->base.height = 32;
48
49   pplayer->size = SMALL;
50   pplayer->got_coffee = NO;
51
52   pplayer->base.x = 0;
53   pplayer->base.y = 240;
54   pplayer->base.xm = 0;
55   pplayer->base.ym = 0;
56   pplayer->old_base = pplayer->base;
57   pplayer->dir = RIGHT;
58   pplayer->duck = NO;
59
60   pplayer->dying = NO;
61   pplayer->jumping = NO;
62
63   pplayer->frame_main = 0;
64   pplayer->frame = 0;
65   pplayer->lives = 3;
66   pplayer->score = 0;
67   pplayer->distros = 0;
68
69   player_input_init(&pplayer->input);
70
71   pplayer->keymap.jump = SDLK_UP;
72   pplayer->keymap.duck = SDLK_DOWN;
73   pplayer->keymap.left = SDLK_LEFT;
74   pplayer->keymap.right = SDLK_RIGHT;
75   pplayer->keymap.fire = SDLK_LCTRL;
76
77   timer_init(&pplayer->invincible_timer,YES);
78   timer_init(&pplayer->skidding_timer,YES);
79   timer_init(&pplayer->safe_timer,YES);
80   timer_init(&pplayer->frame_timer,YES);
81   physic_init(&pplayer->hphysic);
82   physic_init(&pplayer->vphysic);
83 }
84
85 int player_key_event(player_type* pplayer, SDLKey key, int state)
86 {
87   if(key == pplayer->keymap.right)
88     {
89       pplayer->input.right = state;
90       return YES;
91     }
92   else if( key == pplayer->keymap.left)
93     {
94       pplayer->input.left = state;
95       return YES;
96     }
97   else if(key == pplayer->keymap.jump)
98     {
99       pplayer->input.up = state;
100       return YES;
101     }
102   else if(key == pplayer->keymap.duck)
103     {
104       pplayer->input.down = state;
105       return YES;
106     }
107   else if(key == pplayer->keymap.fire)
108     {
109       pplayer->input.fire = state;
110       return YES;
111     }
112   else
113     return NO;
114 }
115
116 void player_level_begin(player_type* pplayer)
117 {
118   pplayer->base.x = 0;
119   pplayer->base.y = 240;
120   pplayer->base.xm = 0;
121   pplayer->base.ym = 0;
122   pplayer->old_base = pplayer->base;
123
124   player_input_init(&pplayer->input);
125
126   timer_init(&pplayer->invincible_timer,YES);
127   timer_init(&pplayer->skidding_timer,YES);
128   timer_init(&pplayer->safe_timer,YES);
129   timer_init(&pplayer->frame_timer,YES);
130   physic_init(&pplayer->hphysic);
131   physic_init(&pplayer->vphysic);
132 }
133
134 void player_action(player_type* pplayer)
135 {
136   int i, jumped_in_solid;
137   jumped_in_solid = NO;
138
139   /* --- HANDLE TUX! --- */
140
141   player_input(pplayer);
142
143   /* Move tux: */
144
145   pplayer->base.x += pplayer->base.xm * frame_ratio;
146   pplayer->base.y += pplayer->base.ym * frame_ratio;
147
148   collision_swept_object_map(&pplayer->old_base,&pplayer->base);
149
150   player_keep_in_bounds(pplayer);
151
152   /* Land: */
153
154   if (!pplayer->dying)
155     {
156
157
158       if( !player_on_ground(pplayer))
159         {
160           if(player_under_solid(pplayer))
161             {
162               physic_set_state(&pplayer->vphysic,PH_VT);
163               physic_set_start_vy(&pplayer->vphysic,0);
164               jumped_in_solid = YES;
165             }
166           else
167             {
168               if(!physic_is_set(&pplayer->vphysic))
169                 {
170                   physic_set_state(&pplayer->vphysic,PH_VT);
171                   physic_set_start_vy(&pplayer->vphysic,0);
172                 }
173             }
174           pplayer->base.ym = physic_get_velocity(&pplayer->vphysic);
175
176         }
177       else
178         {
179
180           /* Land: */
181
182           if (pplayer->base.ym > 0)
183             {
184               pplayer->base.y = (int)(((int)pplayer->base.y / 32) * 32);
185               pplayer->base.ym = 0;
186             }
187
188           physic_init(&pplayer->vphysic);
189         }
190
191
192       if(jumped_in_solid == YES)
193         {
194
195           if (isbrick(pplayer->base.x, pplayer->base.y) ||
196               isfullbox(pplayer->base.x, pplayer->base.y))
197             {
198               trygrabdistro(pplayer->base.x, pplayer->base.y - 32,BOUNCE);
199               trybumpbadguy(pplayer->base.x, pplayer->base.y - 64);
200
201               if(pplayer->size == BIG)
202                 trybreakbrick(pplayer->base.x, pplayer->base.y);
203
204               bumpbrick(pplayer->base.x, pplayer->base.y);
205               tryemptybox(pplayer->base.x, pplayer->base.y);
206             }
207
208           if (isbrick(pplayer->base.x+ 31, pplayer->base.y) ||
209               isfullbox(pplayer->base.x+ 31, pplayer->base.y))
210             {
211               trygrabdistro(pplayer->base.x+ 31, pplayer->base.y - 32,BOUNCE);
212               trybumpbadguy(pplayer->base.x+ 31, pplayer->base.y - 64);
213
214               if(pplayer->size == BIG)
215                 trybreakbrick(pplayer->base.x+ 31, pplayer->base.y);
216
217               bumpbrick(pplayer->base.x+ 31, pplayer->base.y);
218               tryemptybox(pplayer->base.x+ 31, pplayer->base.y);
219             }
220
221
222           if(pplayer->size == SMALL)
223             {
224               /* Get a distro from a brick? */
225
226               if (shape(pplayer->base.x, pplayer->base.y) == 'x' ||
227                   shape(pplayer->base.x, pplayer->base.y) == 'y')
228                 {
229                   add_bouncy_distro((((int)pplayer->base.x)
230                                      / 32) * 32,
231                                     ((int)pplayer->base.y / 32) * 32);
232                   if (counting_distros == NO)
233                     {
234                       counting_distros = YES;
235                       distro_counter = 100;
236                     }
237
238                   if (distro_counter <= 0)
239                     level_change(&current_level,pplayer->base.x,pplayer->base.y - 1, 'a');
240
241                   play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
242                   score = score + SCORE_DISTRO;
243                   distros++;
244                 }
245               else if (shape(pplayer->base.x+ 31, pplayer->base.y) == 'x' ||
246                        shape(pplayer->base.x+ 31, pplayer->base.y) == 'y')
247                 {
248                   add_bouncy_distro((((int)pplayer->base.x + 31)
249                                      / 32) * 32,
250                                     ((int)pplayer->base.y / 32) * 32);
251                   if (counting_distros == NO)
252                     {
253                       counting_distros = YES;
254                       distro_counter = 100;
255                     }
256
257                   if (distro_counter <= 0)
258                     level_change(&current_level,pplayer->base.x+ 31, pplayer->base.y, 'a');
259
260                   play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
261                   score = score + SCORE_DISTRO;
262                   distros++;
263                 }
264             }
265         }
266
267       player_grabdistros(pplayer);
268       if(jumped_in_solid == YES)
269         {
270           ++pplayer->base.y;
271           ++pplayer->old_base.y;
272           if(player_on_ground(pplayer))
273             {
274               /* Make sure jumping is off. */
275               pplayer->jumping = NO;
276             }
277         }
278
279       /* Reset score multiplier (for multi-hits): */
280
281       if (pplayer->base.ym > 2)
282         score_multiplier = 1;
283
284     }
285
286   timer_check(&pplayer->safe_timer);
287
288
289   /* ---- DONE HANDLING TUX! --- */
290
291   /* Handle invincibility timer: */
292
293
294   if (get_current_music() == HERRING_MUSIC && !timer_check(&pplayer->invincible_timer))
295     {
296       /*
297          no, we are no more invincible
298          or we were not in invincible mode
299          but are we in hurry ?
300        */
301
302
303       if (timer_get_left(&time_left) < TIME_WARNING)
304         {
305           /* yes, we are in hurry
306              stop the herring_song, prepare to play the correct
307              fast level_song !
308            */
309           set_current_music(HURRYUP_MUSIC);
310         }
311       else
312         {
313           set_current_music(LEVEL_MUSIC);
314         }
315
316       /* start playing it */
317       play_current_music();
318     }
319
320   /* Handle skidding: */
321
322   timer_check(&pplayer->skidding_timer);
323
324   /* End of level? */
325
326   if (pplayer->base.x - scroll_x >= endpos && endpos != 0)
327     {
328       next_level = 1;
329     }
330
331 }
332
333 int player_on_ground(player_type *pplayer)
334 {
335   if( issolid(pplayer->base.x + pplayer->base.width / 2, pplayer->base.y + pplayer->base.height) ||
336       issolid(pplayer->base.x + 1, pplayer->base.y + pplayer->base.height) ||
337       issolid(pplayer->base.x + pplayer->base.width - 1, pplayer->base.y + pplayer->base.height)  )
338     {
339       return YES;
340     }
341   else
342     {
343       return NO;
344     }
345 }
346
347 int player_under_solid(player_type *pplayer)
348 {
349   if( issolid(pplayer->base.x + pplayer->base.width / 2, pplayer->base.y) ||
350       issolid(pplayer->base.x + 1, pplayer->base.y) ||
351       issolid(pplayer->base.x + pplayer->base.width - 1, pplayer->base.y)  )
352     {
353       return YES;
354     }
355   else
356     {
357       return NO;
358     }
359 }
360
361 void player_handle_horizontal_input(player_type *pplayer, int dir)
362 {
363   if (pplayer->jumping == NO)
364     {
365       if ((dir ? (pplayer->base.xm < -SKID_XM) : (pplayer->base.xm > SKID_XM)) && !timer_started(&pplayer->skidding_timer) &&
366           pplayer->dir == !dir)
367         {
368           timer_start(&pplayer->skidding_timer, SKID_TIME);
369
370           play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
371
372         }
373       pplayer->dir = dir;
374     }
375
376   if ((dir ? (pplayer->base.xm < 0) : (pplayer->base.xm > 0)) && !isice(pplayer->base.x, pplayer->base.y + pplayer->base.height) &&
377       !timer_started(&pplayer->skidding_timer))
378     {
379       pplayer->base.xm = 0;
380     }
381
382   if (!pplayer->duck)
383     {
384       if (pplayer->dir == dir)
385         {
386           /* Facing the direction we're jumping?  Go full-speed: */
387
388           if (pplayer->input.fire == UP)
389             {
390               pplayer->base.xm = pplayer->base.xm + ( dir ? WALK_SPEED : -WALK_SPEED) * frame_ratio;
391
392               if(dir)
393                 {
394                   if (pplayer->base.xm > MAX_WALK_XM)
395                     pplayer->base.xm = MAX_WALK_XM;
396                 }
397               else
398                 {
399                   if (pplayer->base.xm < -MAX_WALK_XM)
400                     pplayer->base.xm = -MAX_WALK_XM;
401                 }
402             }
403           else if ( pplayer->input.fire == DOWN)
404             {
405               pplayer->base.xm = pplayer->base.xm + ( dir ? RUN_SPEED : -RUN_SPEED) * frame_ratio;
406
407               if(dir)
408                 {
409                   if (pplayer->base.xm > MAX_RUN_XM)
410                     pplayer->base.xm = MAX_RUN_XM;
411                 }
412               else
413                 {
414                   if (pplayer->base.xm < -MAX_RUN_XM)
415                     pplayer->base.xm = -MAX_RUN_XM;
416                 }
417             }
418           else
419             {
420               /* Not facing the direction we're jumping?
421               Go half-speed: */
422
423               pplayer->base.xm = pplayer->base.xm + ( dir ? (WALK_SPEED / 2) : -(WALK_SPEED / 2)) * frame_ratio;
424
425               if(dir)
426                 {
427                   if (pplayer->base.xm > MAX_WALK_XM / 2)
428                     pplayer->base.xm = MAX_WALK_XM / 2;
429                 }
430               else
431                 {
432                   if (pplayer->base.xm < -MAX_WALK_XM / 2)
433                     pplayer->base.xm = -MAX_WALK_XM / 2;
434                 }
435             }
436         }
437
438     }
439 }
440
441 void player_handle_vertical_input(player_type *pplayer)
442 {
443   if(pplayer->input.up == DOWN)
444     {
445       if (player_on_ground(pplayer))
446         {
447           if(!physic_is_set(&pplayer->vphysic))
448             {
449               physic_set_state(&pplayer->vphysic,PH_VT);
450               physic_set_start_vy(&pplayer->vphysic,5.5);
451               --pplayer->base.y;
452               pplayer->jumping = YES;
453               if (pplayer->size == SMALL)
454                 play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
455               else
456                 play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
457             }
458         }
459     }
460   else if(pplayer->input.up == UP && pplayer->jumping == YES)
461     {
462       if (player_on_ground(pplayer))
463         {
464           physic_init(&pplayer->vphysic);
465           pplayer->jumping == NO;
466         }
467       else
468         {
469           pplayer->jumping = NO;
470           if(physic_is_set(&pplayer->vphysic))
471             {
472               if(physic_get_velocity(&pplayer->vphysic) < 0.)
473                 {
474                   physic_set_state(&pplayer->vphysic,PH_VT);
475                   physic_set_start_vy(&pplayer->vphysic,0);
476                 }
477             }
478           else
479             {
480               if(!physic_is_set(&pplayer->vphysic))
481                 {
482                   physic_set_state(&pplayer->vphysic,PH_VT);
483                 }
484             }
485         }
486     }
487 }
488
489 void player_input(player_type *pplayer)
490 {
491   /* Handle key and joystick state: */
492
493   if(pplayer->duck == NO)
494     {
495       if (pplayer->input.right == DOWN && pplayer->input.left == UP)
496         {
497           player_handle_horizontal_input(pplayer,RIGHT);
498         }
499       else if (pplayer->input.left == DOWN && pplayer->input.right == UP)
500         {
501           player_handle_horizontal_input(pplayer,LEFT);
502         }
503       else
504         {
505           if(pplayer->base.xm > 0)
506             {
507               pplayer->base.xm = (int)(pplayer->base.xm - frame_ratio);
508               if(pplayer->base.xm < 0)
509                 pplayer->base.xm = 0;
510             }
511           else if(pplayer->base.xm < 0)
512             {
513               pplayer->base.xm = (int)(pplayer->base.xm + frame_ratio);
514               if(pplayer->base.xm > 0)
515                 pplayer->base.xm = 0;
516             }
517         }
518     }
519
520   /* Jump/jumping? */
521
522   if ( pplayer->input.up == DOWN || (pplayer->input.up == UP && pplayer->jumping == YES))
523     {
524       player_handle_vertical_input(pplayer);
525     }
526
527   /* Shoot! */
528
529   if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee)
530     {
531       add_bullet(pplayer->base.x, pplayer->base.y, pplayer->base.xm, pplayer->dir);
532     }
533
534
535   /* Duck! */
536
537   if (pplayer->input.down == DOWN)
538     {
539       if (pplayer->size == BIG && pplayer->duck != YES)
540         {
541           pplayer->duck = YES;
542           pplayer->base.height = 32;
543           pplayer->base.y += 32;
544         }
545     }
546   else
547     {
548       if (pplayer->size == BIG && pplayer->duck == YES)
549         {
550           /* Make sure we're not standing back up into a solid! */
551           pplayer->base.height = 64;
552           pplayer->base.y -= 32;
553
554           if (!collision_object_map(&pplayer->base) /*issolid(pplayer->base.x + 16, pplayer->base.y - 16)*/)
555             {
556               pplayer->duck = NO;
557               pplayer->base.height = 64;
558               pplayer->old_base.y -= 32;
559               pplayer->old_base.height = 64;
560             }
561           else
562             {
563               pplayer->base.height = 32;
564               pplayer->base.y += 32;
565             }
566         }
567       else
568         {
569           pplayer->duck = NO;
570         }
571     }
572
573   /* (Tux): */
574
575   if(!timer_check(&pplayer->frame_timer))
576     {
577       timer_start(&pplayer->frame_timer,25);
578       if (pplayer->input.right == UP && pplayer->input.left == UP)
579         {
580           pplayer->frame_main = 1;
581           pplayer->frame = 1;
582         }
583       else
584         {
585           if ((pplayer->input.fire == DOWN && (frame % 2) == 0) ||
586               (frame % 4) == 0)
587             pplayer->frame_main = (pplayer->frame_main + 1) % 4;
588
589           pplayer->frame = pplayer->frame_main;
590
591           if (pplayer->frame == 3)
592             pplayer->frame = 1;
593         }
594     }
595
596 }
597
598 void player_grabdistros(player_type *pplayer)
599 {
600   /* Grab distros: */
601   if (!pplayer->dying)
602     {
603       trygrabdistro(pplayer->base.x, pplayer->base.y, NO_BOUNCE);
604       trygrabdistro(pplayer->base.x+ 31, pplayer->base.y, NO_BOUNCE);
605
606       trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
607       trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
608
609       if(pplayer->size == BIG)
610         {
611           trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
612           trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
613         }
614
615     }
616
617
618   /* Enough distros for a One-up? */
619
620   if (distros >= DISTROS_LIFEUP)
621     {
622       distros = distros - DISTROS_LIFEUP;
623       if(pplayer->lives < MAX_LIVES)
624         pplayer->lives++;
625       /*We want to hear the sound even, if MAX_LIVES is reached*/
626       play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
627     }
628 }
629
630 void player_draw(player_type* pplayer)
631 {
632   if (!timer_started(&pplayer->safe_timer) || (frame % 2) == 0)
633     {
634       if (pplayer->size == SMALL)
635         {
636           if (timer_started(&pplayer->invincible_timer))
637             {
638               /* Draw cape: */
639
640               if (pplayer->dir == RIGHT)
641                 {
642                   texture_draw(&cape_right[frame % 2],
643                                pplayer->base.x- scroll_x, pplayer->base.y,
644                                NO_UPDATE);
645                 }
646               else
647                 {
648                   texture_draw(&cape_left[frame % 2],
649                                pplayer->base.x- scroll_x, pplayer->base.y,
650                                NO_UPDATE);
651                 }
652             }
653
654
655           if (!pplayer->got_coffee)
656             {
657               if (pplayer->dir == RIGHT)
658                 {
659                   texture_draw(&tux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
660                 }
661               else
662                 {
663                   texture_draw(&tux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
664                 }
665             }
666           else
667             {
668               /* Tux got coffee! */
669
670               if (pplayer->dir == RIGHT)
671                 {
672                   texture_draw(&firetux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
673                 }
674               else
675                 {
676                   texture_draw(&firetux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
677                 }
678             }
679         }
680       else
681         {
682           if (timer_started(&pplayer->invincible_timer))
683             {
684               /* Draw cape: */
685
686               if (pplayer->dir == RIGHT)
687                 {
688                   texture_draw(&bigcape_right[frame % 2],
689                                pplayer->base.x- scroll_x - 8, pplayer->base.y,
690                                NO_UPDATE);
691                 }
692               else
693                 {
694                   texture_draw(&bigcape_left[frame % 2],
695                                pplayer->base.x-scroll_x - 8, pplayer->base.y,
696                                NO_UPDATE);
697                 }
698             }
699
700           if (!pplayer->got_coffee)
701             {
702               if (!pplayer->duck)
703                 {
704                   if (!timer_started(&pplayer->skidding_timer))
705                     {
706                       if (!pplayer->jumping || pplayer->base.ym > 0)
707                         {
708                           if (pplayer->dir == RIGHT)
709                             {
710                               texture_draw(&bigtux_right[pplayer->frame],
711                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
712                                            NO_UPDATE);
713                             }
714                           else
715                             {
716                               texture_draw(&bigtux_left[pplayer->frame],
717                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
718                                            NO_UPDATE);
719                             }
720                         }
721                       else
722                         {
723                           if (pplayer->dir == RIGHT)
724                             {
725                               texture_draw(&bigtux_right_jump,
726                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
727                                            NO_UPDATE);
728                             }
729                           else
730                             {
731                               texture_draw(&bigtux_left_jump,
732                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
733                                            NO_UPDATE);
734                             }
735                         }
736                     }
737                   else
738                     {
739                       if (pplayer->dir == RIGHT)
740                         {
741                           texture_draw(&skidtux_right,
742                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
743                                        NO_UPDATE);
744                         }
745                       else
746                         {
747                           texture_draw(&skidtux_left,
748                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
749                                        NO_UPDATE);
750                         }
751                     }
752                 }
753               else
754                 {
755                   if (pplayer->dir == RIGHT)
756                     {
757                       texture_draw(&ducktux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
758                                    NO_UPDATE);
759                     }
760                   else
761                     {
762                       texture_draw(&ducktux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
763                                    NO_UPDATE);
764                     }
765                 }
766             }
767           else
768             {
769               /* Tux has coffee! */
770
771               if (!pplayer->duck)
772                 {
773                   if (!timer_started(&pplayer->skidding_timer))
774                     {
775                       if (!pplayer->jumping || pplayer->base.ym > 0)
776                         {
777                           if (pplayer->dir == RIGHT)
778                             {
779                               texture_draw(&bigfiretux_right[pplayer->frame],
780                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
781                                            NO_UPDATE);
782                             }
783                           else
784                             {
785                               texture_draw(&bigfiretux_left[pplayer->frame],
786                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
787                                            NO_UPDATE);
788                             }
789                         }
790                       else
791                         {
792                           if (pplayer->dir == RIGHT)
793                             {
794                               texture_draw(&bigfiretux_right_jump,
795                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
796                                            NO_UPDATE);
797                             }
798                           else
799                             {
800                               texture_draw(&bigfiretux_left_jump,
801                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
802                                            NO_UPDATE);
803                             }
804                         }
805                     }
806                   else
807                     {
808                       if (pplayer->dir == RIGHT)
809                         {
810                           texture_draw(&skidfiretux_right,
811                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
812                                        NO_UPDATE);
813                         }
814                       else
815                         {
816                           texture_draw(&skidfiretux_left,
817                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
818                                        NO_UPDATE);
819                         }
820                     }
821                 }
822               else
823                 {
824                   if (pplayer->dir == RIGHT)
825                     {
826                       texture_draw(&duckfiretux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
827                                    NO_UPDATE);
828                     }
829                   else
830                     {
831                       texture_draw(&duckfiretux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
832                                    NO_UPDATE);
833                     }
834                 }
835             }
836         }
837     }
838 }
839
840 void player_collision(player_type* pplayer, void* p_c_object, int c_object)
841 {
842   bad_guy_type* pbad_c = NULL;
843
844   switch (c_object)
845     {
846     case CO_BADGUY:
847       pbad_c = (bad_guy_type*) p_c_object;
848       /* Hurt the player if he just touched it: */
849
850       if (!pbad_c->dying && !pplayer->dying &&
851           !timer_started(&pplayer->safe_timer) &&
852           pbad_c->mode != HELD)
853         {
854           if (pbad_c->mode == FLAT  && pplayer->input.fire != DOWN)
855             {
856               /* Kick: */
857
858               pbad_c->mode = KICK;
859               play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
860
861               if (pplayer->base.x<= pbad_c->base.x)
862                 {
863                   pbad_c->dir = RIGHT;
864                   pbad_c->base.x = pbad_c->base.x + 16;
865                 }
866               else
867                 {
868                   pbad_c->dir = LEFT;
869                   pbad_c->base.x = pbad_c->base.x - 32;
870                 }
871
872               timer_start(&pbad_c->timer,5000);
873             }
874           else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
875             {
876               pbad_c->mode = HELD;
877               pbad_c->base.y-=8;
878             }
879           else if (pbad_c->mode == KICK)
880             {
881               if (pplayer->base.y < pbad_c->base.y - 16 &&
882                   timer_started(&pbad_c->timer))
883                 {
884                   /* Step on (stop being kicked) */
885
886                   pbad_c->mode = FLAT;
887                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
888                   timer_start(&pbad_c->timer, 10000);
889                 }
890               else
891                 {
892                   /* Hurt if you get hit by kicked laptop: */
893
894                   if (timer_started(&pbad_c->timer))
895                     {
896                       if (!timer_started(&pplayer->invincible_timer))
897                         {
898                           player_kill(pplayer,SHRINK);
899                         }
900                       else
901                         {
902                           pbad_c->dying = FALLING;
903                           physic_set_state(&pplayer->vphysic,PH_VT);
904                           physic_set_start_vy(&pplayer->vphysic,-2.);
905                           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
906                         }
907                     }
908                 }
909             }
910           else
911             {
912               if (!timer_started(&pplayer->invincible_timer ))
913                 {
914                   player_kill(pplayer,SHRINK);
915                 }
916               else
917                 {
918                   pbad_c->dying = FALLING;
919                   physic_set_state(&pplayer->vphysic,PH_VT);
920                   physic_set_start_vy(&pplayer->vphysic,-2.);
921                   play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
922                 }
923             }
924           score_multiplier++;
925         }
926       break;
927     default:
928       break;
929     }
930
931 }
932
933 /* Kill Player! */
934
935 void player_kill(player_type* pplayer, int mode)
936 {
937   pplayer->base.ym = -5;
938
939   play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
940
941   if (pplayer->dir == RIGHT)
942     pplayer->base.xm = -8;
943   else if (pplayer->dir == LEFT)
944     pplayer->base.xm = 8;
945
946   if (mode == SHRINK && pplayer->size == BIG)
947     {
948       if (pplayer->got_coffee)
949         pplayer->got_coffee = NO;
950
951       pplayer->size = SMALL;
952       pplayer->base.height = 32;
953
954       timer_start(&pplayer->safe_timer,TUX_SAFE_TIME);
955     }
956   else
957     {
958       pplayer->dying = 1;
959     }
960 }
961
962 void player_dying(player_type *pplayer)
963 {
964   pplayer->base.ym = pplayer->base.ym + gravity;
965
966   /* He died :^( */
967
968   --pplayer->lives;
969   player_remove_powerups(pplayer);
970   pplayer->dying = NO;
971
972   player_level_begin(pplayer);
973
974 }
975
976 /* Remove Tux's power ups */
977 void player_remove_powerups(player_type* pplayer)
978 {
979   pplayer->got_coffee = NO;
980   pplayer->size = SMALL;
981   pplayer->base.height = 32;
982 }
983
984 void player_keep_in_bounds(player_type* pplayer)
985 {
986   /* Keep tux in bounds: */
987   if (pplayer->base.x< 0)
988     pplayer->base.x= 0;
989   else if(pplayer->base.x< scroll_x)
990     pplayer->base.x= scroll_x;
991   else if (pplayer->base.x< 160 + scroll_x && scroll_x > 0 && debug_mode == YES)
992     {
993       scroll_x = pplayer->base.x- 160;
994       /*pplayer->base.x+= 160;*/
995
996       if(scroll_x < 0)
997         scroll_x = 0;
998
999     }
1000   else if (pplayer->base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
1001     {
1002       /* Scroll the screen in past center: */
1003
1004       scroll_x = pplayer->base.x- screen->w / 2;
1005       /*pplayer->base.x= 320 + scroll_x;*/
1006
1007       if (scroll_x > ((current_level.width * 32) - screen->w))
1008         scroll_x = ((current_level.width * 32) - screen->w);
1009     }
1010   else if (pplayer->base.x> 608 + scroll_x)
1011     {
1012       /* ... unless there's no more to scroll! */
1013
1014       /*pplayer->base.x= 608 + scroll_x;*/
1015     }
1016
1017   /* Keep in-bounds, vertically: */
1018
1019   if (pplayer->base.y > screen->h)
1020     {
1021       player_kill(&tux,KILL);
1022     }
1023 }