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