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