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