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