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