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