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