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