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