Yet another huge code merge representing the current status of my rewrite. It include...
[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
715     if (!timer_started(&pplayer->safe_timer) || (frame % 2) == 0)
716       {
717         if (pplayer->size == SMALL)
718           {
719             if (timer_started(&pplayer->invincible_timer))
720               {
721                 /* Draw cape: */
722
723                 if (pplayer->dir == RIGHT)
724                   {
725                     texture_draw(&cape_right[frame % 2],
726                                  pplayer->base.x- scroll_x, pplayer->base.y,
727                                  NO_UPDATE);
728                   }
729                 else
730                   {
731                     texture_draw(&cape_left[frame % 2],
732                                  pplayer->base.x- scroll_x, pplayer->base.y,
733                                  NO_UPDATE);
734                   }
735               }
736
737
738             if (!pplayer->got_coffee)
739               {
740                 if (pplayer->dir == RIGHT)
741                   {
742                     texture_draw(&tux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
743                   }
744                 else
745                   {
746                     texture_draw(&tux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
747                   }
748               }
749             else
750               {
751                 /* Tux got coffee! */
752
753                 if (pplayer->dir == RIGHT)
754                   {
755                     texture_draw(&firetux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
756                   }
757                 else
758                   {
759                     texture_draw(&firetux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
760                   }
761               }
762           }
763         else
764           {
765             if (timer_started(&pplayer->invincible_timer))
766               {
767                 /* Draw cape: */
768
769                 if (pplayer->dir == RIGHT)
770                   {
771                     texture_draw(&bigcape_right[frame % 2],
772                                  pplayer->base.x- scroll_x - 8 - 16, pplayer->base.y - 32,
773                                  NO_UPDATE);
774                   }
775                 else
776                   {
777                     texture_draw(&bigcape_left[frame % 2],
778                                  pplayer->base.x-scroll_x - 8, pplayer->base.y - 32,
779                                  NO_UPDATE);
780                   }
781               }
782
783             if (!pplayer->got_coffee)
784               {
785                 if (!pplayer->duck)
786                   {
787                     if (!timer_started(&pplayer->skidding_timer))
788                       {
789                         if (!pplayer->jumping || pplayer->base.ym > 0)
790                           {
791                             if (pplayer->dir == RIGHT)
792                               {
793                                 texture_draw(&bigtux_right[pplayer->frame],
794                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
795                                              NO_UPDATE);
796                               }
797                             else
798                               {
799                                 texture_draw(&bigtux_left[pplayer->frame],
800                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
801                                              NO_UPDATE);
802                               }
803                           }
804                         else
805                           {
806                             if (pplayer->dir == RIGHT)
807                               {
808                                 texture_draw(&bigtux_right_jump,
809                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
810                                              NO_UPDATE);
811                               }
812                             else
813                               {
814                                 texture_draw(&bigtux_left_jump,
815                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
816                                              NO_UPDATE);
817                               }
818                           }
819                       }
820                     else
821                       {
822                         if (pplayer->dir == RIGHT)
823                           {
824                             texture_draw(&skidtux_right,
825                                          pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
826                                          NO_UPDATE);
827                           }
828                         else
829                           {
830                             texture_draw(&skidtux_left,
831                                          pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
832                                          NO_UPDATE);
833                           }
834                       }
835                   }
836                 else
837                   {
838                     if (pplayer->dir == RIGHT)
839                       {
840                         texture_draw(&ducktux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
841                                      NO_UPDATE);
842                       }
843                     else
844                       {
845                         texture_draw(&ducktux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
846                                      NO_UPDATE);
847                       }
848                   }
849               }
850             else
851               {
852                 /* Tux has coffee! */
853
854                 if (!pplayer->duck)
855                   {
856                     if (!timer_started(&pplayer->skidding_timer))
857                       {
858                         if (!pplayer->jumping || pplayer->base.ym > 0)
859                           {
860                             if (pplayer->dir == RIGHT)
861                               {
862                                 texture_draw(&bigfiretux_right[pplayer->frame],
863                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
864                                              NO_UPDATE);
865                               }
866                             else
867                               {
868                                 texture_draw(&bigfiretux_left[pplayer->frame],
869                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
870                                              NO_UPDATE);
871                               }
872                           }
873                         else
874                           {
875                             if (pplayer->dir == RIGHT)
876                               {
877                                 texture_draw(&bigfiretux_right_jump,
878                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
879                                              NO_UPDATE);
880                               }
881                             else
882                               {
883                                 texture_draw(&bigfiretux_left_jump,
884                                              pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
885                                              NO_UPDATE);
886                               }
887                           }
888                       }
889                     else
890                       {
891                         if (pplayer->dir == RIGHT)
892                           {
893                             texture_draw(&skidfiretux_right,
894                                          pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
895                                          NO_UPDATE);
896                           }
897                         else
898                           {
899                             texture_draw(&skidfiretux_left,
900                                          pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
901                                          NO_UPDATE);
902                           }
903                       }
904                   }
905                 else
906                   {
907                     if (pplayer->dir == RIGHT)
908                       {
909                         texture_draw(&duckfiretux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
910                                      NO_UPDATE);
911                       }
912                     else
913                       {
914                         texture_draw(&duckfiretux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
915                                      NO_UPDATE);
916                       }
917                   }
918               }
919           }
920       }
921
922   }
923
924   void player_collision(player_type* pplayer, void* p_c_object, int c_object)
925   {
926     bad_guy_type* pbad_c = NULL;
927
928     switch (c_object)
929       {
930       case CO_BADGUY:
931         pbad_c = p_c_object;
932         /* Hurt the player if he just touched it: */
933
934         if (!pbad_c->dying && !pplayer->dying &&
935             !timer_started(&pplayer->safe_timer) &&
936             pbad_c->mode != HELD)
937           {
938             if (pbad_c->mode == FLAT  && pplayer->input.fire != DOWN)
939               {
940                 /* Kick: */
941
942                 pbad_c->mode = KICK;
943                 play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
944
945                 if (pplayer->base.x<= pbad_c->base.x)
946                   {
947                     pbad_c->dir = RIGHT;
948                     pbad_c->base.x = pbad_c->base.x + 16;
949                   }
950                 else
951                   {
952                     pbad_c->dir = LEFT;
953                     pbad_c->base.x = pbad_c->base.x - 16;
954                   }
955
956                 timer_start(&pbad_c->timer,5000);
957               }
958             else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
959               {
960                 pbad_c->mode = HELD;
961                 pbad_c->base.y-=8;
962               }
963             else if (pbad_c->mode == KICK)
964               {
965                 if (pplayer->base.y < pbad_c->base.y - 16 &&
966                     timer_started(&pbad_c->timer))
967                   {
968                     /* Step on (stop being kicked) */
969
970                     pbad_c->mode = FLAT;
971                     play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
972                     timer_start(&pbad_c->timer, 10000);
973                   }
974                 else
975                   {
976                     /* Hurt if you get hit by kicked laptop: */
977
978                     if (timer_started(&pbad_c->timer))
979                       {
980                         if (!timer_started(&pplayer->invincible_timer))
981                           {
982                             player_kill(pplayer,SHRINK);
983                           }
984                         else
985                           {
986                             pbad_c->dying = FALLING;
987                             pbad_c->base.ym = -8;
988                             play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
989                           }
990                       }
991                   }
992               }
993             else
994               {
995                 if (!timer_started(&pplayer->invincible_timer ))
996                   {
997                     player_kill(pplayer,SHRINK);
998                   }
999                 else
1000                   {
1001                     pbad_c->dying = FALLING;
1002                     pbad_c->base.ym = -8;
1003                     play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1004                   }
1005               }
1006           }
1007         score_multiplier++;
1008         break;
1009       }
1010
1011   }
1012
1013   /* Kill Player! */
1014
1015   void player_kill(player_type* pplayer, int mode)
1016   {
1017     pplayer->base.ym = -5;
1018
1019     play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
1020
1021     if (pplayer->dir == RIGHT)
1022       pplayer->base.xm = -8;
1023     else if (pplayer->dir == LEFT)
1024       pplayer->base.xm = 8;
1025
1026     if (mode == SHRINK && pplayer->size == BIG)
1027       {
1028         if (pplayer->got_coffee)
1029           pplayer->got_coffee = NO;
1030
1031         pplayer->size = SMALL;
1032
1033         timer_start(&pplayer->safe_timer,TUX_SAFE_TIME);
1034       }
1035     else
1036       {
1037         pplayer->dying = 1;
1038       }
1039   }
1040
1041   void player_dying(player_type *pplayer)
1042   {
1043     pplayer->base.ym = pplayer->base.ym + GRAVITY;
1044
1045     /* He died :^( */
1046
1047     --pplayer->lives;
1048     player_remove_powerups(pplayer);
1049     pplayer->dying = NO;
1050
1051     player_level_begin(pplayer);
1052
1053   }
1054
1055   /* Remove Tux's power ups */
1056   void player_remove_powerups(player_type* pplayer)
1057   {
1058     pplayer->got_coffee = NO;
1059     pplayer->size = SMALL;
1060   }
1061
1062   void player_keep_in_bounds(player_type* pplayer)
1063   {
1064     /* Keep tux in bounds: */
1065     if (pplayer->base.x< 0)
1066       pplayer->base.x= 0;
1067     else if(pplayer->base.x< scroll_x)
1068       pplayer->base.x= scroll_x;
1069     else if (pplayer->base.x< 160 + scroll_x && scroll_x > 0 && debug_mode == YES)
1070       {
1071         scroll_x = pplayer->base.x- 160;
1072         /*pplayer->base.x+= 160;*/
1073
1074         if(scroll_x < 0)
1075           scroll_x = 0;
1076
1077       }
1078     else if (pplayer->base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
1079       {
1080         /* Scroll the screen in past center: */
1081
1082         scroll_x = pplayer->base.x- screen->w / 2;
1083         /*pplayer->base.x= 320 + scroll_x;*/
1084
1085         if (scroll_x > ((current_level.width * 32) - screen->w))
1086           scroll_x = ((current_level.width * 32) - screen->w);
1087       }
1088     else if (pplayer->base.x> 608 + scroll_x)
1089       {
1090         /* ... unless there's no more to scroll! */
1091
1092         /*pplayer->base.x= 608 + scroll_x;*/
1093       }
1094
1095     /* Keep in-bounds, vertically: */
1096
1097     if (pplayer->base.y < 0)
1098       pplayer->base.y = 0;
1099     else if (pplayer->base.y > screen->h)
1100       {
1101         player_kill(&tux,KILL);
1102       }
1103   }