fixed save/load-game.
[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
494   if (pplayer->input.right == DOWN && pplayer->input.left == UP)
495     {
496       player_handle_horizontal_input(pplayer,RIGHT);
497     }
498   else if (pplayer->input.left == DOWN && pplayer->input.right == UP)
499     {
500       player_handle_horizontal_input(pplayer,LEFT);
501     }
502   else
503     {
504       if(pplayer->base.xm > 0)
505         {
506           pplayer->base.xm = (int)(pplayer->base.xm - frame_ratio);
507           if(pplayer->base.xm < 0)
508             pplayer->base.xm = 0;
509         }
510       else if(pplayer->base.xm < 0)
511         {
512           pplayer->base.xm = (int)(pplayer->base.xm + frame_ratio);
513           if(pplayer->base.xm > 0)
514             pplayer->base.xm = 0;
515         }
516     }
517
518   /* Jump/jumping? */
519
520   if ( pplayer->input.up == DOWN || (pplayer->input.up == UP && pplayer->jumping == YES))
521     {
522       player_handle_vertical_input(pplayer);
523     }
524
525   /* Shoot! */
526
527   if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee)
528     {
529       add_bullet(pplayer->base.x, pplayer->base.y, pplayer->base.xm, pplayer->dir);
530     }
531
532
533   /* Duck! */
534
535   if (pplayer->input.down == DOWN)
536     {
537       if (pplayer->size == BIG && pplayer->duck != YES)
538         {
539           pplayer->duck = YES;
540           pplayer->base.height = 32;
541           pplayer->base.y += 32;
542         }
543     }
544   else
545     {
546       if (pplayer->size == BIG && pplayer->duck == YES)
547         {
548           /* Make sure we're not standing back up into a solid! */
549           pplayer->base.height = 64;
550           pplayer->base.y -= 32;
551
552           if (!collision_object_map(&pplayer->base) /*issolid(pplayer->base.x + 16, pplayer->base.y - 16)*/)
553             {
554               pplayer->duck = NO;
555               pplayer->base.height = 64;
556               pplayer->old_base.y -= 32;
557               pplayer->old_base.height = 64;
558             }
559           else
560             {
561               pplayer->base.height = 32;
562               pplayer->base.y += 32;
563             }
564         }
565       else
566         {
567           pplayer->duck = NO;
568         }
569     }
570
571   /* (Tux): */
572
573   if(!timer_check(&pplayer->frame_timer))
574     {
575       timer_start(&pplayer->frame_timer,25);
576       if (pplayer->input.right == UP && pplayer->input.left == UP)
577         {
578           pplayer->frame_main = 1;
579           pplayer->frame = 1;
580         }
581       else
582         {
583           if ((pplayer->input.fire == DOWN && (frame % 2) == 0) ||
584               (frame % 4) == 0)
585             pplayer->frame_main = (pplayer->frame_main + 1) % 4;
586
587           pplayer->frame = pplayer->frame_main;
588
589           if (pplayer->frame == 3)
590             pplayer->frame = 1;
591         }
592     }
593
594 }
595
596 void player_grabdistros(player_type *pplayer)
597 {
598   /* Grab distros: */
599   if (!pplayer->dying)
600     {
601       trygrabdistro(pplayer->base.x, pplayer->base.y, NO_BOUNCE);
602       trygrabdistro(pplayer->base.x+ 31, pplayer->base.y, NO_BOUNCE);
603
604       trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
605       trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
606
607       if(pplayer->size == BIG)
608         {
609           trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
610           trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
611         }
612
613     }
614
615
616   /* Enough distros for a One-up? */
617
618   if (distros >= DISTROS_LIFEUP)
619     {
620       distros = distros - DISTROS_LIFEUP;
621       if(pplayer->lives < MAX_LIVES)
622         pplayer->lives++;
623       /*We want to hear the sound even, if MAX_LIVES is reached*/
624       play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
625     }
626 }
627
628 void player_draw(player_type* pplayer)
629 {
630   if (!timer_started(&pplayer->safe_timer) || (frame % 2) == 0)
631     {
632       if (pplayer->size == SMALL)
633         {
634           if (timer_started(&pplayer->invincible_timer))
635             {
636               /* Draw cape: */
637
638               if (pplayer->dir == RIGHT)
639                 {
640                   texture_draw(&cape_right[frame % 2],
641                                pplayer->base.x- scroll_x, pplayer->base.y,
642                                NO_UPDATE);
643                 }
644               else
645                 {
646                   texture_draw(&cape_left[frame % 2],
647                                pplayer->base.x- scroll_x, pplayer->base.y,
648                                NO_UPDATE);
649                 }
650             }
651
652
653           if (!pplayer->got_coffee)
654             {
655               if (pplayer->dir == RIGHT)
656                 {
657                   texture_draw(&tux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
658                 }
659               else
660                 {
661                   texture_draw(&tux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
662                 }
663             }
664           else
665             {
666               /* Tux got coffee! */
667
668               if (pplayer->dir == RIGHT)
669                 {
670                   texture_draw(&firetux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
671                 }
672               else
673                 {
674                   texture_draw(&firetux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
675                 }
676             }
677         }
678       else
679         {
680           if (timer_started(&pplayer->invincible_timer))
681             {
682               /* Draw cape: */
683
684               if (pplayer->dir == RIGHT)
685                 {
686                   texture_draw(&bigcape_right[frame % 2],
687                                pplayer->base.x- scroll_x - 8, pplayer->base.y,
688                                NO_UPDATE);
689                 }
690               else
691                 {
692                   texture_draw(&bigcape_left[frame % 2],
693                                pplayer->base.x-scroll_x - 8, pplayer->base.y,
694                                NO_UPDATE);
695                 }
696             }
697
698           if (!pplayer->got_coffee)
699             {
700               if (!pplayer->duck)
701                 {
702                   if (!timer_started(&pplayer->skidding_timer))
703                     {
704                       if (!pplayer->jumping || pplayer->base.ym > 0)
705                         {
706                           if (pplayer->dir == RIGHT)
707                             {
708                               texture_draw(&bigtux_right[pplayer->frame],
709                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
710                                            NO_UPDATE);
711                             }
712                           else
713                             {
714                               texture_draw(&bigtux_left[pplayer->frame],
715                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
716                                            NO_UPDATE);
717                             }
718                         }
719                       else
720                         {
721                           if (pplayer->dir == RIGHT)
722                             {
723                               texture_draw(&bigtux_right_jump,
724                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
725                                            NO_UPDATE);
726                             }
727                           else
728                             {
729                               texture_draw(&bigtux_left_jump,
730                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
731                                            NO_UPDATE);
732                             }
733                         }
734                     }
735                   else
736                     {
737                       if (pplayer->dir == RIGHT)
738                         {
739                           texture_draw(&skidtux_right,
740                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
741                                        NO_UPDATE);
742                         }
743                       else
744                         {
745                           texture_draw(&skidtux_left,
746                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
747                                        NO_UPDATE);
748                         }
749                     }
750                 }
751               else
752                 {
753                   if (pplayer->dir == RIGHT)
754                     {
755                       texture_draw(&ducktux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
756                                    NO_UPDATE);
757                     }
758                   else
759                     {
760                       texture_draw(&ducktux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
761                                    NO_UPDATE);
762                     }
763                 }
764             }
765           else
766             {
767               /* Tux has coffee! */
768
769               if (!pplayer->duck)
770                 {
771                   if (!timer_started(&pplayer->skidding_timer))
772                     {
773                       if (!pplayer->jumping || pplayer->base.ym > 0)
774                         {
775                           if (pplayer->dir == RIGHT)
776                             {
777                               texture_draw(&bigfiretux_right[pplayer->frame],
778                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
779                                            NO_UPDATE);
780                             }
781                           else
782                             {
783                               texture_draw(&bigfiretux_left[pplayer->frame],
784                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
785                                            NO_UPDATE);
786                             }
787                         }
788                       else
789                         {
790                           if (pplayer->dir == RIGHT)
791                             {
792                               texture_draw(&bigfiretux_right_jump,
793                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
794                                            NO_UPDATE);
795                             }
796                           else
797                             {
798                               texture_draw(&bigfiretux_left_jump,
799                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
800                                            NO_UPDATE);
801                             }
802                         }
803                     }
804                   else
805                     {
806                       if (pplayer->dir == RIGHT)
807                         {
808                           texture_draw(&skidfiretux_right,
809                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
810                                        NO_UPDATE);
811                         }
812                       else
813                         {
814                           texture_draw(&skidfiretux_left,
815                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
816                                        NO_UPDATE);
817                         }
818                     }
819                 }
820               else
821                 {
822                   if (pplayer->dir == RIGHT)
823                     {
824                       texture_draw(&duckfiretux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
825                                    NO_UPDATE);
826                     }
827                   else
828                     {
829                       texture_draw(&duckfiretux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
830                                    NO_UPDATE);
831                     }
832                 }
833             }
834         }
835     }
836 }
837
838 void player_collision(player_type* pplayer, void* p_c_object, int c_object)
839 {
840   bad_guy_type* pbad_c = NULL;
841
842   switch (c_object)
843     {
844     case CO_BADGUY:
845       pbad_c = (bad_guy_type*) p_c_object;
846       /* Hurt the player if he just touched it: */
847
848       if (!pbad_c->dying && !pplayer->dying &&
849           !timer_started(&pplayer->safe_timer) &&
850           pbad_c->mode != HELD)
851         {
852           if (pbad_c->mode == FLAT  && pplayer->input.fire != DOWN)
853             {
854               /* Kick: */
855
856               pbad_c->mode = KICK;
857               play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
858
859               if (pplayer->base.x<= pbad_c->base.x)
860                 {
861                   pbad_c->dir = RIGHT;
862                   pbad_c->base.x = pbad_c->base.x + 16;
863                 }
864               else
865                 {
866                   pbad_c->dir = LEFT;
867                   pbad_c->base.x = pbad_c->base.x - 32;   
868                 }
869              
870              timer_start(&pbad_c->timer,5000);
871             }
872           else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
873             {
874               pbad_c->mode = HELD;
875               pbad_c->base.y-=8;
876             }
877           else if (pbad_c->mode == KICK)
878             {
879               if (pplayer->base.y < pbad_c->base.y - 16 &&
880                   timer_started(&pbad_c->timer))
881                 {
882                   /* Step on (stop being kicked) */
883
884                   pbad_c->mode = FLAT;
885                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
886                   timer_start(&pbad_c->timer, 10000);
887                 }
888               else
889                 {
890                   /* Hurt if you get hit by kicked laptop: */
891
892                   if (timer_started(&pbad_c->timer))
893                     {
894                       if (!timer_started(&pplayer->invincible_timer))
895                         {
896                           player_kill(pplayer,SHRINK);
897                         }
898                       else
899                         {
900                           pbad_c->dying = FALLING;
901                           physic_set_state(&pplayer->vphysic,PH_VT);
902                           physic_set_start_vy(&pplayer->vphysic,-2.);
903                           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
904                         }
905                     }
906                 }
907             }
908           else
909             {
910               if (!timer_started(&pplayer->invincible_timer ))
911                 {
912                   player_kill(pplayer,SHRINK);
913                 }
914               else
915                 {
916                   pbad_c->dying = FALLING;
917                   physic_set_state(&pplayer->vphysic,PH_VT);
918                   physic_set_start_vy(&pplayer->vphysic,-2.);
919                   play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
920                 }
921             }
922           score_multiplier++;
923         }
924       break;
925     default:
926       break;
927     }
928
929 }
930
931 /* Kill Player! */
932
933 void player_kill(player_type* pplayer, int mode)
934 {
935   pplayer->base.ym = -5;
936
937   play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
938
939   if (pplayer->dir == RIGHT)
940     pplayer->base.xm = -8;
941   else if (pplayer->dir == LEFT)
942     pplayer->base.xm = 8;
943
944   if (mode == SHRINK && pplayer->size == BIG)
945     {
946       if (pplayer->got_coffee)
947         pplayer->got_coffee = NO;
948
949       pplayer->size = SMALL;
950       pplayer->base.height = 32;
951
952       timer_start(&pplayer->safe_timer,TUX_SAFE_TIME);
953     }
954   else
955     {
956       pplayer->dying = 1;
957     }
958 }
959
960 void player_dying(player_type *pplayer)
961 {
962   pplayer->base.ym = pplayer->base.ym + gravity;
963
964   /* He died :^( */
965
966   --pplayer->lives;
967   player_remove_powerups(pplayer);
968   pplayer->dying = NO;
969
970   player_level_begin(pplayer);
971
972 }
973
974 /* Remove Tux's power ups */
975 void player_remove_powerups(player_type* pplayer)
976 {
977   pplayer->got_coffee = NO;
978   pplayer->size = SMALL;
979   pplayer->base.height = 32;
980 }
981
982 void player_keep_in_bounds(player_type* pplayer)
983 {
984   /* Keep tux in bounds: */
985   if (pplayer->base.x< 0)
986     pplayer->base.x= 0;
987   else if(pplayer->base.x< scroll_x)
988     pplayer->base.x= scroll_x;
989   else if (pplayer->base.x< 160 + scroll_x && scroll_x > 0 && debug_mode == YES)
990     {
991       scroll_x = pplayer->base.x- 160;
992       /*pplayer->base.x+= 160;*/
993
994       if(scroll_x < 0)
995         scroll_x = 0;
996
997     }
998   else if (pplayer->base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
999     {
1000       /* Scroll the screen in past center: */
1001
1002       scroll_x = pplayer->base.x- screen->w / 2;
1003       /*pplayer->base.x= 320 + scroll_x;*/
1004
1005       if (scroll_x > ((current_level.width * 32) - screen->w))
1006         scroll_x = ((current_level.width * 32) - screen->w);
1007     }
1008   else if (pplayer->base.x> 608 + scroll_x)
1009     {
1010       /* ... unless there's no more to scroll! */
1011
1012       /*pplayer->base.x= 608 + scroll_x;*/
1013     }
1014
1015   /* Keep in-bounds, vertically: */
1016
1017   if (pplayer->base.y > screen->h)
1018     {
1019       player_kill(&tux,KILL);
1020     }
1021 }