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