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