more gameplay improvements. level-editor is getting closer to a useable state . etc.
[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         pplayer->base.xm = (int)(pplayer->base.xm - frame_ratio);
886       else if(pplayer->base.xm < 0)
887         pplayer->base.xm = (int)(pplayer->base.xm + frame_ratio);
888     }
889
890   /* Jump/jumping? */
891
892   if ( pplayer->input.up == DOWN || (pplayer->input.up == UP && pplayer->jumping == YES))
893     {
894       player_handle_vertical_input(pplayer);
895     }
896
897   /* Shoot! */
898
899   if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee)
900     {
901       add_bullet(pplayer->base.x, pplayer->base.y, pplayer->base.xm, pplayer->dir);
902     }
903
904
905   /* Duck! */
906
907   if (pplayer->input.down == DOWN)
908     {
909       if (pplayer->size == BIG)
910         pplayer->duck = YES;
911     }
912   else
913     {
914       if (pplayer->size == BIG && pplayer->duck == YES)
915         {
916           /* Make sure we're not standing back up into a solid! */
917
918           if (!issolid(pplayer->base.x + 16, pplayer->base.y - 16))
919             pplayer->duck = NO;
920         }
921       else
922         pplayer->duck = NO;
923     }
924
925   /* (Tux): */
926
927   if(!timer_check(&pplayer->frame_timer))
928     {
929       timer_start(&pplayer->frame_timer,25);
930       if (pplayer->input.right == UP && pplayer->input.left == UP)
931         {
932           pplayer->frame_main = 1;
933           pplayer->frame = 1;
934         }
935       else
936         {
937           if ((pplayer->input.fire == DOWN && (frame % 2) == 0) ||
938               (frame % 4) == 0)
939             pplayer->frame_main = (pplayer->frame_main + 1) % 4;
940
941           pplayer->frame = pplayer->frame_main;
942
943           if (pplayer->frame == 3)
944             pplayer->frame = 1;
945         }
946     }
947
948 }
949
950 void player_grabdistros(player_type *pplayer)
951 {
952   /* Grab distros: */
953   if (!pplayer->dying)
954     {
955       trygrabdistro(pplayer->base.x, pplayer->base.y, NO_BOUNCE);
956       trygrabdistro(pplayer->base.x+ 31, pplayer->base.y, NO_BOUNCE);
957
958       trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
959       trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
960
961       if(pplayer->size == BIG)
962         {
963           trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
964           trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
965         }
966
967     }
968
969
970   /* Enough distros for a One-up? */
971
972   if (distros >= DISTROS_LIFEUP)
973     {
974       distros = distros - DISTROS_LIFEUP;
975       if(pplayer->lives < MAX_LIVES)
976         pplayer->lives++;
977       /*We want to hear the sound even, if MAX_LIVES is reached*/
978       play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
979     }
980 }
981
982 void player_draw(player_type* pplayer)
983 {
984   if (!timer_started(&pplayer->safe_timer) || (frame % 2) == 0)
985     {
986       if (pplayer->size == SMALL)
987         {
988           if (timer_started(&pplayer->invincible_timer))
989             {
990               /* Draw cape: */
991
992               if (pplayer->dir == RIGHT)
993                 {
994                   texture_draw(&cape_right[frame % 2],
995                                pplayer->base.x- scroll_x, pplayer->base.y,
996                                NO_UPDATE);
997                 }
998               else
999                 {
1000                   texture_draw(&cape_left[frame % 2],
1001                                pplayer->base.x- scroll_x, pplayer->base.y,
1002                                NO_UPDATE);
1003                 }
1004             }
1005
1006
1007           if (!pplayer->got_coffee)
1008             {
1009               if (pplayer->dir == RIGHT)
1010                 {
1011                   texture_draw(&tux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
1012                 }
1013               else
1014                 {
1015                   texture_draw(&tux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
1016                 }
1017             }
1018           else
1019             {
1020               /* Tux got coffee! */
1021
1022               if (pplayer->dir == RIGHT)
1023                 {
1024                   texture_draw(&firetux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
1025                 }
1026               else
1027                 {
1028                   texture_draw(&firetux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
1029                 }
1030             }
1031         }
1032       else
1033         {
1034           if (timer_started(&pplayer->invincible_timer))
1035             {
1036               /* Draw cape: */
1037
1038               if (pplayer->dir == RIGHT)
1039                 {
1040                   texture_draw(&bigcape_right[frame % 2],
1041                                pplayer->base.x- scroll_x - 8, pplayer->base.y,
1042                                NO_UPDATE);
1043                 }
1044               else
1045                 {
1046                   texture_draw(&bigcape_left[frame % 2],
1047                                pplayer->base.x-scroll_x - 8, pplayer->base.y,
1048                                NO_UPDATE);
1049                 }
1050             }
1051
1052           if (!pplayer->got_coffee)
1053             {
1054               if (!pplayer->duck)
1055                 {
1056                   if (!timer_started(&pplayer->skidding_timer))
1057                     {
1058                       if (!pplayer->jumping || pplayer->base.ym > 0)
1059                         {
1060                           if (pplayer->dir == RIGHT)
1061                             {
1062                               texture_draw(&bigtux_right[pplayer->frame],
1063                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1064                                            NO_UPDATE);
1065                             }
1066                           else
1067                             {
1068                               texture_draw(&bigtux_left[pplayer->frame],
1069                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1070                                            NO_UPDATE);
1071                             }
1072                         }
1073                       else
1074                         {
1075                           if (pplayer->dir == RIGHT)
1076                             {
1077                               texture_draw(&bigtux_right_jump,
1078                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1079                                            NO_UPDATE);
1080                             }
1081                           else
1082                             {
1083                               texture_draw(&bigtux_left_jump,
1084                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1085                                            NO_UPDATE);
1086                             }
1087                         }
1088                     }
1089                   else
1090                     {
1091                       if (pplayer->dir == RIGHT)
1092                         {
1093                           texture_draw(&skidtux_right,
1094                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
1095                                        NO_UPDATE);
1096                         }
1097                       else
1098                         {
1099                           texture_draw(&skidtux_left,
1100                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
1101                                        NO_UPDATE);
1102                         }
1103                     }
1104                 }
1105               else
1106                 {
1107                   if (pplayer->dir == RIGHT)
1108                     {
1109                       texture_draw(&ducktux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y,
1110                                    NO_UPDATE);
1111                     }
1112                   else
1113                     {
1114                       texture_draw(&ducktux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y,
1115                                    NO_UPDATE);
1116                     }
1117                 }
1118             }
1119           else
1120             {
1121               /* Tux has coffee! */
1122
1123               if (!pplayer->duck)
1124                 {
1125                   if (!timer_started(&pplayer->skidding_timer))
1126                     {
1127                       if (!pplayer->jumping || pplayer->base.ym > 0)
1128                         {
1129                           if (pplayer->dir == RIGHT)
1130                             {
1131                               texture_draw(&bigfiretux_right[pplayer->frame],
1132                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1133                                            NO_UPDATE);
1134                             }
1135                           else
1136                             {
1137                               texture_draw(&bigfiretux_left[pplayer->frame],
1138                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1139                                            NO_UPDATE);
1140                             }
1141                         }
1142                       else
1143                         {
1144                           if (pplayer->dir == RIGHT)
1145                             {
1146                               texture_draw(&bigfiretux_right_jump,
1147                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1148                                            NO_UPDATE);
1149                             }
1150                           else
1151                             {
1152                               texture_draw(&bigfiretux_left_jump,
1153                                            pplayer->base.x- scroll_x - 8, pplayer->base.y,
1154                                            NO_UPDATE);
1155                             }
1156                         }
1157                     }
1158                   else
1159                     {
1160                       if (pplayer->dir == RIGHT)
1161                         {
1162                           texture_draw(&skidfiretux_right,
1163                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
1164                                        NO_UPDATE);
1165                         }
1166                       else
1167                         {
1168                           texture_draw(&skidfiretux_left,
1169                                        pplayer->base.x- scroll_x - 8, pplayer->base.y,
1170                                        NO_UPDATE);
1171                         }
1172                     }
1173                 }
1174               else
1175                 {
1176                   if (pplayer->dir == RIGHT)
1177                     {
1178                       texture_draw(&duckfiretux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y,
1179                                    NO_UPDATE);
1180                     }
1181                   else
1182                     {
1183                       texture_draw(&duckfiretux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y,
1184                                    NO_UPDATE);
1185                     }
1186                 }
1187             }
1188         }
1189     }
1190 }
1191
1192 void player_collision(player_type* pplayer, void* p_c_object, int c_object)
1193 {
1194   bad_guy_type* pbad_c = NULL;
1195
1196   switch (c_object)
1197     {
1198     case CO_BADGUY:
1199       pbad_c = (bad_guy_type*) p_c_object;
1200       /* Hurt the player if he just touched it: */
1201
1202       if (!pbad_c->dying && !pplayer->dying &&
1203           !timer_started(&pplayer->safe_timer) &&
1204           pbad_c->mode != HELD)
1205         {
1206           if (pbad_c->mode == FLAT  && pplayer->input.fire != DOWN)
1207             {
1208               /* Kick: */
1209
1210               pbad_c->mode = KICK;
1211               play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
1212
1213               if (pplayer->base.x<= pbad_c->base.x)
1214                 {
1215                   pbad_c->dir = RIGHT;
1216                   pbad_c->base.x = pbad_c->base.x + 16;
1217                 }
1218               else
1219                 {
1220                   pbad_c->dir = LEFT;
1221                   pbad_c->base.x = pbad_c->base.x - 16;
1222                 }
1223
1224               timer_start(&pbad_c->timer,5000);
1225             }
1226           else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
1227             {
1228               pbad_c->mode = HELD;
1229               pbad_c->base.y-=8;
1230             }
1231           else if (pbad_c->mode == KICK)
1232             {
1233               if (pplayer->base.y < pbad_c->base.y - 16 &&
1234                   timer_started(&pbad_c->timer))
1235                 {
1236                   /* Step on (stop being kicked) */
1237
1238                   pbad_c->mode = FLAT;
1239                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
1240                   timer_start(&pbad_c->timer, 10000);
1241                 }
1242               else
1243                 {
1244                   /* Hurt if you get hit by kicked laptop: */
1245
1246                   if (timer_started(&pbad_c->timer))
1247                     {
1248                       if (!timer_started(&pplayer->invincible_timer))
1249                         {
1250                           player_kill(pplayer,SHRINK);
1251                         }
1252                       else
1253                         {
1254                           pbad_c->dying = FALLING;
1255                           physic_set_state(&pplayer->vphysic,PH_VT);
1256                           physic_set_start_vy(&pplayer->vphysic,-2.);
1257                           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1258                         }
1259                     }
1260                 }
1261             }
1262           else
1263             {
1264               if (!timer_started(&pplayer->invincible_timer ))
1265                 {
1266                   player_kill(pplayer,SHRINK);
1267                 }
1268               else
1269                 {
1270                   pbad_c->dying = FALLING;
1271                   physic_set_state(&pplayer->vphysic,PH_VT);
1272                   physic_set_start_vy(&pplayer->vphysic,-2.);
1273                   play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1274                 }
1275             }
1276           score_multiplier++;
1277         }
1278       break;
1279     default:
1280       break;
1281     }
1282
1283 }
1284
1285 /* Kill Player! */
1286
1287 void player_kill(player_type* pplayer, int mode)
1288 {
1289   pplayer->base.ym = -5;
1290
1291   play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
1292
1293   if (pplayer->dir == RIGHT)
1294     pplayer->base.xm = -8;
1295   else if (pplayer->dir == LEFT)
1296     pplayer->base.xm = 8;
1297
1298   if (mode == SHRINK && pplayer->size == BIG)
1299     {
1300       if (pplayer->got_coffee)
1301         pplayer->got_coffee = NO;
1302
1303       pplayer->size = SMALL;
1304       pplayer->base.height = 32;
1305
1306       timer_start(&pplayer->safe_timer,TUX_SAFE_TIME);
1307     }
1308   else
1309     {
1310       pplayer->dying = 1;
1311     }
1312 }
1313
1314 void player_dying(player_type *pplayer)
1315 {
1316   pplayer->base.ym = pplayer->base.ym + gravity;
1317
1318   /* He died :^( */
1319
1320   --pplayer->lives;
1321   player_remove_powerups(pplayer);
1322   pplayer->dying = NO;
1323
1324   player_level_begin(pplayer);
1325
1326 }
1327
1328 /* Remove Tux's power ups */
1329 void player_remove_powerups(player_type* pplayer)
1330 {
1331   pplayer->got_coffee = NO;
1332   pplayer->size = SMALL;
1333   pplayer->base.height = 32;
1334 }
1335
1336 void player_keep_in_bounds(player_type* pplayer)
1337 {
1338   /* Keep tux in bounds: */
1339   if (pplayer->base.x< 0)
1340     pplayer->base.x= 0;
1341   else if(pplayer->base.x< scroll_x)
1342     pplayer->base.x= scroll_x;
1343   else if (pplayer->base.x< 160 + scroll_x && scroll_x > 0 && debug_mode == YES)
1344     {
1345       scroll_x = pplayer->base.x- 160;
1346       /*pplayer->base.x+= 160;*/
1347
1348       if(scroll_x < 0)
1349         scroll_x = 0;
1350
1351     }
1352   else if (pplayer->base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
1353     {
1354       /* Scroll the screen in past center: */
1355
1356       scroll_x = pplayer->base.x- screen->w / 2;
1357       /*pplayer->base.x= 320 + scroll_x;*/
1358
1359       if (scroll_x > ((current_level.width * 32) - screen->w))
1360         scroll_x = ((current_level.width * 32) - screen->w);
1361     }
1362   else if (pplayer->base.x> 608 + scroll_x)
1363     {
1364       /* ... unless there's no more to scroll! */
1365
1366       /*pplayer->base.x= 608 + scroll_x;*/
1367     }
1368
1369   /* Keep in-bounds, vertically: */
1370
1371   if (pplayer->base.y < 0)
1372     pplayer->base.y = 0;
1373   else if (pplayer->base.y > screen->h)
1374     {
1375       player_kill(&tux,KILL);
1376     }
1377 }