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