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