Just a small fix to prevent Tux from butt-jumping when ducked.
[supertux.git] / src / player.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <math.h>
21 #include <iostream>
22 #include <cassert>
23 #include "gameloop.h"
24 #include "globals.h"
25 #include "player.h"
26 #include "defines.h"
27 #include "scene.h"
28 #include "tile.h"
29 #include "sprite.h"
30 #include "sector.h"
31 #include "tilemap.h"
32 #include "camera.h"
33 #include "gameobjs.h"
34 #include "resources.h"
35 #include "interactive_object.h"
36 #include "screen/screen.h"
37
38 // behavior definitions:
39 #define TILES_FOR_BUTTJUMP 3
40 // animation times (in ms):
41 #define SHOOTING_TIME 320
42 // others stuff:
43 #define AUTOSCROLL_DEAD_INTERVAL 300
44
45 // growing animation
46 Surface* growingtux_left[GROWING_FRAMES];
47 Surface* growingtux_right[GROWING_FRAMES];
48
49 Surface* tux_life;
50
51 Sprite* smalltux_gameover;
52 Sprite* smalltux_star;
53 Sprite* largetux_star;
54
55 PlayerSprite smalltux;
56 PlayerSprite largetux;
57 PlayerSprite icetux;
58 PlayerSprite firetux;
59
60 PlayerKeymap keymap;
61
62 PlayerKeymap::PlayerKeymap()
63 {
64   keymap.jump  = SDLK_SPACE;
65   keymap.activate = SDLK_UP;
66   keymap.duck  = SDLK_DOWN;
67   keymap.left  = SDLK_LEFT;
68   keymap.right = SDLK_RIGHT;
69   keymap.fire  = SDLK_LCTRL;
70 }
71
72 void player_input_init(player_input_type* pplayer_input)
73 {
74   pplayer_input->down = UP;
75   pplayer_input->fire = UP;
76   pplayer_input->left = UP;
77   pplayer_input->old_fire = UP;
78   pplayer_input->right = UP;
79   pplayer_input->up = UP;
80   pplayer_input->old_up = UP;
81   pplayer_input->activate = UP;
82 }
83
84 Player::Player()
85 {
86   init();
87 }
88
89 Player::~Player()
90 {
91 }
92
93 void
94 Player::init()
95 {
96   holding_something = false;
97
98   base.width = 32;
99   base.height = 32;
100
101   size = SMALL;
102   got_power = NONE_POWER;
103
104   base.x = 0;
105   base.y = 0;
106   previous_base = old_base = base;
107   dir = RIGHT;
108   old_dir = dir;
109   duck = false;
110   dead = false;
111
112   dying   = DYING_NOT;
113   last_ground_y = 0;
114   fall_mode = ON_GROUND;
115   jumping = false;
116   can_jump = true;
117   butt_jump = false;
118
119   frame_main = 0;
120   frame_ = 0;
121
122   player_input_init(&input);
123
124   invincible_timer.init(true);
125   skidding_timer.init(true);
126   safe_timer.init(true);
127   frame_timer.init(true);
128   kick_timer.init(true);
129   shooting_timer.init(true);
130   growing_timer.init(true);
131
132   physic.reset();
133 }
134
135 int
136 Player::key_event(SDLKey key, int state)
137 {
138   if(key == keymap.right)
139     {
140       input.right = state;
141       return true;
142     }
143   else if(key == keymap.left)
144     {
145       input.left = state;
146       return true;
147     }
148   else if(key == keymap.jump)
149     {
150       input.up = state;
151       return true;
152     }
153   else if(key == keymap.duck)
154     {
155       input.down = state;
156       return true;
157     }
158   else if(key == keymap.fire)
159     {
160       if (state == UP)
161         input.old_fire = UP;
162       input.fire = state;
163       return true;
164     }
165   else if(key == keymap.activate)
166     {
167       input.activate = state;
168
169       if(state == DOWN) {
170         /** check for interactive objects */
171         for(Sector::InteractiveObjects::iterator i 
172             = Sector::current()->interactive_objects.begin();
173             i != Sector::current()->interactive_objects.end(); ++i) {
174           if(rectcollision(base, (*i)->get_area())) {
175             (*i)->interaction(INTERACTION_ACTIVATE);
176           }
177         }
178       }
179       
180       return true;
181     }
182   else
183     return false;
184 }
185
186 void
187 Player::level_begin()
188 {
189   base.x  = 100;
190   base.y  = 170;
191   previous_base = old_base = base;
192   duck = false;
193
194   dying = DYING_NOT;
195
196   player_input_init(&input);
197
198   invincible_timer.init(true);
199   skidding_timer.init(true);
200   safe_timer.init(true);
201   frame_timer.init(true);
202   growing_timer.init(true);
203
204   physic.reset();
205 }
206
207 void
208 Player::action(float elapsed_time)
209 {
210   bool jumped_in_solid = false;
211
212   if(dying && !dying_timer.check()) {
213     dead = true;
214     return;
215   }
216
217   if (input.fire == UP)
218     holding_something = false;
219
220   /* Move tux: */
221   previous_base = base;
222
223   /* --- HANDLE TUX! --- */
224   if(dying == DYING_NOT)
225     handle_input();
226
227   physic.apply(elapsed_time, base.x, base.y);
228
229   if(dying == DYING_NOT) 
230     {
231       base_type target = base;
232
233       collision_swept_object_map(&old_base, &base);
234
235       if ((!invincible_timer.started() && !safe_timer.started())
236           && (isspike(base.x, base.y) || isspike(base.x + base.width, base.y)
237           ||  isspike(base.x, base.y + base.height)
238           ||  isspike(base.x + base.width, base.y + base.height)))
239       {
240          kill(SHRINK);
241       }
242
243       // Don't accelerate Tux if he is running against a wall
244       if (target.x != base.x)
245         {
246           physic.set_velocity_x(0);
247         }
248
249       // special exception for cases where we're stuck under tiles after
250       // being ducked. In this case we drift out
251       if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
252          && collision_object_map(base))
253         {
254           base.x += elapsed_time * WALK_SPEED * (dir ? 1: -1);
255           previous_base = old_base = base;
256         }
257
258       // Land:
259       if (!on_ground())
260         {
261           physic.enable_gravity(true);
262           if(under_solid())
263             {
264               // fall down
265               physic.set_velocity_y(0);
266               jumped_in_solid = true;
267               jumping = false;
268             }
269         }
270       else
271         {
272           /* Land: */
273           if (physic.get_velocity_y() < 0)
274             {
275               base.y = (int)(((int)base.y / 32) * 32);
276               physic.set_velocity_y(0);
277             }
278
279           physic.enable_gravity(false);
280           /* Reset score multiplier (for multi-hits): */
281           if (!invincible_timer.started())
282             player_status.score_multiplier = 1;
283         }
284
285       if(jumped_in_solid)
286         {
287           if (isbrick(base.x, base.y) ||
288               isfullbox(base.x, base.y))
289             {
290               Sector::current()->trygrabdistro(
291                   Vector(base.x, base.y - 32), BOUNCE);
292               Sector::current()->trybumpbadguy(Vector(base.x, base.y - 64));
293
294               Sector::current()->trybreakbrick(
295                   Vector(base.x, base.y), size == SMALL);
296
297               bumpbrick(base.x, base.y);
298               Sector::current()->tryemptybox(Vector(base.x, base.y), RIGHT);
299             }
300
301           if (isbrick(base.x+ 31, base.y) ||
302               isfullbox(base.x+ 31, base.y))
303             {
304               Sector::current()->trygrabdistro(
305                   Vector(base.x+ 31, base.y - 32), BOUNCE);
306               Sector::current()->trybumpbadguy(Vector(base.x+ 31, base.y - 64));
307
308               if(size == BIG)
309                 Sector::current()->trybreakbrick(
310                     Vector(base.x+ 31, base.y), size == SMALL);
311
312               bumpbrick(base.x+ 31, base.y);
313               Sector::current()->tryemptybox(Vector(base.x+ 31, base.y), LEFT);
314             }
315         }
316
317       grabdistros();
318
319       if (jumped_in_solid)
320         {
321           ++base.y;
322           ++old_base.y;
323           if(on_ground())
324             {
325               /* Make sure jumping is off. */
326               jumping = false;
327             }
328         }
329     }
330
331   /* ---- DONE HANDLING TUX! --- */
332
333   // check some timers
334   skidding_timer.check();
335   invincible_timer.check();
336   safe_timer.check();
337   kick_timer.check();
338 }
339
340 bool
341 Player::on_ground()
342 {
343   return ( issolid(base.x + base.width / 2, base.y + base.height) ||
344            issolid(base.x + 1, base.y + base.height) ||
345            issolid(base.x + base.width - 1, base.y + base.height));
346 }
347
348 bool
349 Player::under_solid()
350 {
351   return ( issolid(base.x + base.width / 2, base.y) ||
352            issolid(base.x + 1, base.y) ||
353            issolid(base.x + base.width - 1, base.y)  );
354 }
355
356 bool
357 Player::tiles_on_air(int tiles)
358 {
359   for(int t = 0; t != tiles; t++)
360      {
361      if(issolid(base.x + base.width / 2, base.y + base.height + (tiles*32)) ||
362          issolid(base.x + 1, base.y + base.height + (tiles*32)) ||
363          issolid(base.x + base.width - 1, base.y + base.height + (tiles*32)))
364        return false;
365      }
366   return true;
367 }
368
369 void
370 Player::handle_horizontal_input()
371 {
372   float vx = physic.get_velocity_x();
373   float vy = physic.get_velocity_y();
374   float ax = physic.get_acceleration_x();
375   float ay = physic.get_acceleration_y();
376
377   float dirsign = 0;
378   if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
379       old_dir = dir;
380       dir = LEFT;
381       dirsign = -1;
382   } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
383       old_dir = dir;
384       dir = RIGHT;
385       dirsign = 1;
386   }
387
388   if (input.fire == UP) {
389       ax = dirsign * WALK_ACCELERATION_X;
390       // limit speed
391       if(vx >= MAX_WALK_XM && dirsign > 0) {
392         vx = MAX_WALK_XM;
393         ax = 0;
394       } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
395         vx = -MAX_WALK_XM;
396         ax = 0;
397       }
398   } else {
399       ax = dirsign * RUN_ACCELERATION_X;
400       // limit speed
401       if(vx >= MAX_RUN_XM && dirsign > 0) {
402         vx = MAX_RUN_XM;
403         ax = 0;
404       } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
405         vx = -MAX_RUN_XM;
406         ax = 0;
407       }
408   }
409
410   // we can reach WALK_SPEED without any acceleration
411   if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
412     vx = dirsign * WALK_SPEED;
413   }
414
415   // changing directions?
416   if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0))) {
417       if(fabs(vx)>SKID_XM && !skidding_timer.check()) {
418           skidding_timer.start(SKID_TIME);
419           sound_manager->play_sound(sounds[SND_SKID]);
420           ax *= 2.5;
421       } else {
422           ax *= 2;
423       }
424   }
425
426   // we get slower when not pressing any keys
427   if(dirsign == 0) {
428       if(fabs(vx) < WALK_SPEED) {
429           vx = 0;
430           ax = 0;
431       } else if(vx < 0) {
432           ax = WALK_ACCELERATION_X * 1.5;
433       } else {
434           ax = WALK_ACCELERATION_X * -1.5;
435       }
436   }
437
438   // if we're on ice slow down acceleration or deceleration
439   if (isice(base.x, base.y + base.height))
440   {
441     /* the acceleration/deceleration rate on ice is inversely proportional to
442      * the current velocity.
443      */
444
445     // increasing 1 will increase acceleration/deceleration rate
446     // decreasing 1 will decrease acceleration/deceleration rate
447     //  must stay above zero, though
448     if (ax != 0) ax *= 1 / fabs(vx);
449   }
450
451   physic.set_velocity(vx, vy);
452   physic.set_acceleration(ax, ay);
453 }
454
455 void
456 Player::handle_vertical_input()
457 {
458   // set fall mode...
459   if(on_ground()) {
460     fall_mode = ON_GROUND;
461     last_ground_y = base.y;
462   } else {
463     if(base.y > last_ground_y)
464       fall_mode = FALLING;
465     else if(fall_mode == ON_GROUND)
466       fall_mode = JUMPING;
467   }
468
469   // Press jump key
470   if(input.up == DOWN && can_jump && on_ground())
471     {
472       if(duck) { // only jump a little bit when in duck mode {
473         physic.set_velocity_y(3);
474       } else {
475         // jump higher if we are running
476         if (fabs(physic.get_velocity_x()) > MAX_WALK_XM)
477           physic.set_velocity_y(5.8);
478         else
479           physic.set_velocity_y(5.2);
480       }
481
482       --base.y;
483       jumping = true;
484       can_jump = false;
485       if (size == SMALL)
486         sound_manager->play_sound(sounds[SND_JUMP]);
487       else
488         sound_manager->play_sound(sounds[SND_BIGJUMP]);
489     }
490   // Let go of jump key
491   else if(input.up == UP && jumping && physic.get_velocity_y() > 0)
492     {
493       jumping = false;
494       physic.set_velocity_y(0);
495     }
496
497    /* In case the player has pressed Down while in a certain range of air,
498       enable butt jump action */
499   if (input.down == DOWN && !butt_jump && !duck)
500     if(tiles_on_air(TILES_FOR_BUTTJUMP) && jumping)
501       butt_jump = true;
502
503    /* When Down is not held anymore, disable butt jump */
504   if(butt_jump && input.down == UP)
505     butt_jump = false;
506
507   // Do butt jump
508   if (butt_jump && on_ground() && size == BIG)
509   {
510     butt_jump = false;
511
512     // Break bricks beneath Tux
513     if(Sector::current()->trybreakbrick(
514           Vector(base.x + 1, base.y + base.height), false)
515         || Sector::current()->trybreakbrick(
516            Vector(base.x + base.width - 1, base.y + base.height), false))
517     {
518       physic.set_velocity_y(2);
519       butt_jump = true;
520     }
521
522     // Kill nearby badguys
523     std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
524     for (std::vector<GameObject*>::iterator i = gameobjects.begin();
525          i != gameobjects.end();
526          i++)
527     {
528       BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
529       if(badguy)
530       {
531         if (fabsf(base.x - badguy->base.x) < 300 &&
532             fabsf(base.y - badguy->base.y) < 300 &&
533             (issolid(badguy->base.x + 1, badguy->base.y + badguy->base.height) ||
534               issolid(badguy->base.x + badguy->base.width - 1, badguy->base.y + badguy->base.height)))
535           badguy->kill_me(25);
536       }
537     }
538   }
539
540   if ( (issolid(base.x + base.width / 2, base.y + base.height + 64) ||
541         issolid(base.x + 1, base.y + base.height + 64) ||
542         issolid(base.x + base.width - 1, base.y + base.height + 64))
543        && jumping  == false
544        && can_jump == false
545        && input.up == DOWN
546        && input.old_up == UP)
547     {
548       can_jump = true;
549     }
550
551   if(on_ground())   /* Make sure jumping is off. */
552     jumping = false;
553
554   input.old_up = input.up;
555 }
556
557 void
558 Player::handle_input()
559 {
560   /* Handle horizontal movement: */
561     handle_horizontal_input();
562
563   /* Jump/jumping? */
564
565   if (on_ground() && input.up == UP)
566     can_jump = true;
567   handle_vertical_input();
568
569   /* Shoot! */
570   if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER)
571     {
572       if(Sector::current()->add_bullet(Vector(base.x, base.y + (base.height/2)),
573           physic.get_velocity_x(), dir))
574         shooting_timer.start(SHOOTING_TIME);
575       input.old_fire = DOWN;
576     }
577
578   /* tux animations: */
579   if(!frame_timer.check())
580     {
581       frame_timer.start(25);
582       if (input.right == UP && input.left == UP)
583         {
584           frame_main = 1;
585           frame_ = 1;
586         }
587       else
588         {
589           if ((input.fire == DOWN && (global_frame_counter % 2) == 0) ||
590               (global_frame_counter % 4) == 0)
591             frame_main = (frame_main + 1) % 4;
592
593           frame_ = frame_main;
594
595           if (frame_ == 3)
596             frame_ = 1;
597         }
598     }
599
600   /* Duck! */
601   if (input.down == DOWN && size == BIG && !duck && physic.get_velocity_y() == 0 && on_ground())
602     {
603       duck = true;
604       base.height = 32;                             
605       base.y += 32;
606       // changing base size confuses collision otherwise
607       old_base = previous_base = base;
608     }
609   else if(input.down == UP && size == BIG && duck)
610     {
611       // try if we can really unduck
612       base.y -= 32;
613       base.height = 64;
614       // when unducking in air we need some space to do so
615       if(on_ground() || !collision_object_map(base)) {
616         duck = false;
617         // changing base size confuses collision otherwise
618         old_base = previous_base = base;                                
619       } else {
620         // undo the ducking changes
621         base.y += 32;
622         base.height = 32;
623       }   
624     }
625 }
626
627 void
628 Player::grow(bool animate)
629 {
630   if(size == BIG)
631     return;
632   
633   size = BIG;
634   base.height = 64;
635   base.y -= 32;
636
637   if(animate)
638     growing_timer.start(GROWING_TIME);
639
640   old_base = previous_base = base;
641 }
642
643 void
644 Player::grabdistros()
645 {
646   /* Grab distros: */
647   if (!dying)
648     {
649       Sector::current()->trygrabdistro(Vector(base.x, base.y), NO_BOUNCE);
650       Sector::current()->trygrabdistro(Vector(base.x+ 31, base.y), NO_BOUNCE);
651
652       Sector::current()->trygrabdistro(
653           Vector(base.x, base.y + base.height), NO_BOUNCE);
654       Sector::current()->trygrabdistro(
655           Vector(base.x+ 31, base.y + base.height), NO_BOUNCE);
656
657       if(size == BIG)
658         {
659           Sector::current()->trygrabdistro(
660               Vector(base.x, base.y + base.height / 2), NO_BOUNCE);
661           Sector::current()->trygrabdistro(
662               Vector(base.x+ 31, base.y + base.height / 2), NO_BOUNCE);
663         }
664
665     }
666
667   /* Enough distros for a One-up? */
668   if (player_status.distros >= DISTROS_LIFEUP)
669     {
670       player_status.distros = player_status.distros - DISTROS_LIFEUP;
671       if(player_status.lives < MAX_LIVES)
672         ++player_status.lives;
673       /*We want to hear the sound even, if MAX_LIVES is reached*/
674       sound_manager->play_sound(sounds[SND_LIFEUP]);
675     }
676 }
677
678 void
679 Player::draw(DrawingContext& context)
680 {
681   PlayerSprite* sprite;
682           
683   if (size == SMALL)
684     sprite = &smalltux;
685   else if (got_power == FIRE_POWER)
686     sprite = &firetux;
687   else if (got_power == ICE_POWER)
688     sprite = &icetux;
689   else
690     sprite = &largetux;
691
692   int layer = LAYER_OBJECTS - 1;
693   Vector pos = Vector(base.x, base.y);
694
695   if (!safe_timer.started() || (global_frame_counter % 2) == 0)
696     {
697       if (dying == DYING_SQUISHED)
698         {
699           smalltux_gameover->draw(context, pos, LAYER_OBJECTS+1);
700         }
701       else
702         {
703           if(growing_timer.check())
704             {
705               if (dir == RIGHT)
706                 context.draw_surface(growingtux_right[(growing_timer.get_gone() * GROWING_FRAMES) / GROWING_TIME], pos, layer);
707               else 
708                 context.draw_surface(growingtux_left[(growing_timer.get_gone() * GROWING_FRAMES) / GROWING_TIME], pos, layer);
709             }
710           else if (duck && size != SMALL)
711             {
712               if (dir == RIGHT)
713                 sprite->duck_right->draw(context, pos, layer);
714               else 
715                 sprite->duck_left->draw(context, pos, layer);
716             }
717           else if (skidding_timer.started())
718             {
719               if (dir == RIGHT)
720                 sprite->skid_right->draw(context, pos, layer);
721               else
722                 sprite->skid_left->draw(context, pos, layer);
723             }
724           else if (kick_timer.started())
725             {
726               if (dir == RIGHT)
727                 sprite->kick_right->draw(context, pos, layer);
728               else
729                 sprite->kick_left->draw(context, pos, layer);
730             }
731           else if (physic.get_velocity_y() != 0)
732             {
733               if (dir == RIGHT)
734                 sprite->jump_right->draw(context, pos, layer);
735               else
736                 sprite->jump_left->draw(context, pos, layer);
737             }
738           else
739             {
740               if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
741                 {
742                   if (dir == RIGHT)
743                     sprite->stand_right->draw(context, pos, layer);
744                   else
745                     sprite->stand_left->draw(context, pos, layer);
746                 }
747               else // moving
748                 {
749                   if (dir == RIGHT)
750                     sprite->walk_right->draw(context, pos, layer);
751                   else
752                     sprite->walk_left->draw(context, pos, layer);
753                 }
754             }
755         }
756     }     
757
758   // Draw arm overlay graphics when Tux is holding something
759   if ((holding_something && physic.get_velocity_y() == 0) || shooting_timer.check() && !duck)
760   {
761     if (dir == RIGHT)
762       sprite->grab_right->draw(context, pos, LAYER_OBJECTS + 1);
763     else
764       sprite->grab_left->draw(context, pos, LAYER_OBJECTS + 1);
765   }
766
767   // Draw blinking star overlay
768   if (invincible_timer.started() &&
769       (invincible_timer.get_left() > TUX_INVINCIBLE_TIME_WARNING || global_frame_counter % 3))
770   {
771     if (size == SMALL || duck)
772       smalltux_star->draw(context, pos, LAYER_OBJECTS + 2);
773     else
774       largetux_star->draw(context, pos, LAYER_OBJECTS + 2);
775   }
776  
777   if (debug_mode)
778     context.draw_filled_rect(Vector(base.x, base.y),
779         Vector(base.width, base.height), Color(75,75,75, 150), LAYER_OBJECTS+1);
780 }
781
782 void
783 Player::collision(const MovingObject& other, int collision_type)
784 {
785   (void) other;
786   (void) collision_type;
787   // will be implemented later
788 }
789
790 void
791 Player::collision(void* p_c_object, int c_object)
792 {
793   BadGuy* pbad_c = NULL;
794   Trampoline* ptramp_c = NULL;
795   FlyingPlatform* pplatform_c = NULL;
796
797   switch (c_object)
798     {
799     case CO_BADGUY:
800       pbad_c = (BadGuy*) p_c_object;
801
802      /* Hurt player if he touches a badguy */
803       if (!pbad_c->dying && !dying &&
804           !safe_timer.started() &&
805           pbad_c->mode != BadGuy::HELD)
806         {
807           if (pbad_c->mode == BadGuy::FLAT && input.fire == DOWN
808                && !holding_something)
809             {
810               holding_something = true;
811               pbad_c->mode = BadGuy::HELD;
812               pbad_c->base.y-=8;
813             }
814           else if (pbad_c->mode == BadGuy::FLAT)
815             {
816               // Don't get hurt if we're kicking a flat badguy!
817             }
818           else if (pbad_c->mode == BadGuy::KICK)
819             {
820               /* Hurt if you get hit by kicked laptop: */
821               if (!invincible_timer.started())
822                 {
823                   kill(SHRINK);
824                 }
825               else
826                 pbad_c->kill_me(20);
827             }
828           else if (pbad_c->frozen_timer.check() && (pbad_c->kind == BAD_MRBOMB
829               || pbad_c->kind == BAD_JUMPY || pbad_c->kind == BAD_FISH
830               || pbad_c->kind == BAD_SPIKY))
831                 pbad_c->kill_me(20);
832           else
833             {
834               if (!invincible_timer.started())
835                 {
836                   kill(SHRINK);
837                 }
838               else
839                 {
840                   pbad_c->kill_me(25);
841                 }
842             }
843           player_status.score_multiplier++;
844         }
845       break;
846
847     case CO_TRAMPOLINE:
848       ptramp_c = (Trampoline*) p_c_object;
849       
850       // Pick up trampoline
851       if (ptramp_c->mode != Trampoline::M_HELD && input.fire == DOWN && !holding_something && on_ground())
852       {
853         holding_something = true;
854         ptramp_c->mode = Trampoline::M_HELD;
855         ptramp_c->base.y -= 8;
856       }
857       // Set down trampoline
858       else if (ptramp_c->mode == Trampoline::M_HELD && input.fire != DOWN)
859       {
860         holding_something = false;
861         ptramp_c->mode = Trampoline::M_NORMAL;
862         ptramp_c->base.y += 8;
863         ptramp_c->physic.set_velocity(physic.get_velocity_x(), physic.get_velocity_y());
864
865         //if (dir == RIGHT)
866         //  ptramp_c->base.x = base.x + base.width+1;
867         //else /* LEFT */
868         //  ptramp_c->base.x = base.x - base.width-1;
869       }
870 /*
871       // Don't let tux walk through trampoline
872       else if (ptramp_c->mode != Trampoline::M_HELD && on_ground())
873       {
874         if (physic.get_velocity_x() > 0) // RIGHT
875         {
876           physic.set_velocity_x(0);
877           base.x = ptramp_c->base.x - base.width;
878         }
879         else if (physic.get_velocity_x() < 0) // LEFT
880         {
881           physic.set_velocity_x(0);
882           base.x = ptramp_c->base.x + ptramp_c->base.width;
883         }
884       }
885 */
886       break;
887     case CO_FLYING_PLATFORM:
888       pplatform_c = (FlyingPlatform*) p_c_object;
889       
890       base.y = pplatform_c->base.y - base.height;
891       physic.set_velocity_x(pplatform_c->get_vel_x());
892       
893       physic.enable_gravity(false);
894       can_jump = true;
895       fall_mode = ON_GROUND;
896       break;
897
898     default:
899       break;
900     }
901
902 }
903
904 /* Kill Player! */
905
906 void
907 Player::kill(HurtMode mode)
908 {
909   if(dying)
910     return;
911   
912   sound_manager->play_sound(sounds[SND_HURT]);
913
914   physic.set_velocity_x(0);
915
916   if (mode == SHRINK && size == BIG)
917     {
918       if (got_power != NONE_POWER)
919         {
920           got_power = NONE_POWER;
921         }
922       else
923         {
924           size = SMALL;
925           base.height = 32;
926           duck = false;
927         }
928       safe_timer.start(TUX_SAFE_TIME);
929     }
930   else
931     {
932       physic.enable_gravity(true);
933       physic.set_acceleration(0, 0);
934       physic.set_velocity(0, 7);
935       --player_status.lives;
936       dying = DYING_SQUISHED;
937       dying_timer.start(3000);
938     }
939 }
940
941 /* Remove Tux's power ups */
942 void
943 Player::remove_powerups()
944 {
945   got_power = NONE_POWER;
946   size = SMALL;
947   base.height = 32;
948 }
949
950 void
951 Player::move(const Vector& vector)
952 {
953   base.x = vector.x;
954   base.y = vector.y;
955   old_base = previous_base = base;
956 }
957
958 void
959 Player::check_bounds(Camera* camera)
960 {
961   /* Keep tux in bounds: */
962   if (base.x < 0)
963     { // Lock Tux to the size of the level, so that he doesn't fall of
964       // on the left side
965       base.x = 0;
966     }
967
968   /* Keep in-bounds, vertically: */
969   if (base.y > Sector::current()->solids->get_height() * 32)
970     {
971       kill(KILL);
972       return;
973     }
974
975   bool adjust = false;
976   // can happen if back scrolling is disabled
977   if(base.x < camera->get_translation().x) {
978     base.x = camera->get_translation().x;
979     adjust = true;
980   }
981   if(base.x >= camera->get_translation().x + screen->w - base.width) {
982     base.x = camera->get_translation().x + screen->w - base.width;
983     adjust = true;
984   }
985
986   if(adjust) {
987     // squished now?
988     if(collision_object_map(base)) {
989       kill(KILL);
990       return;
991     }
992   }
993 }
994