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