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