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