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