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