Tweaked the buttstomp range - now it kills only enemies that are close to Tux on...
[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         
532         if (fabsf(base.x - badguy->base.x) < 150 &&
533             fabsf(base.y - badguy->base.y) < 60 &&
534             (issolid(badguy->base.x + 1, badguy->base.y + badguy->base.height) ||
535               issolid(badguy->base.x + badguy->base.width - 1, badguy->base.y + badguy->base.height)))
536           badguy->kill_me(25);
537       }
538     }
539   }
540
541   if ( (issolid(base.x + base.width / 2, base.y + base.height + 64) ||
542         issolid(base.x + 1, base.y + base.height + 64) ||
543         issolid(base.x + base.width - 1, base.y + base.height + 64))
544        && jumping  == false
545        && can_jump == false
546        && input.up == DOWN
547        && input.old_up == UP)
548     {
549       can_jump = true;
550     }
551
552   if(on_ground())   /* Make sure jumping is off. */
553     jumping = false;
554
555   input.old_up = input.up;
556 }
557
558 void
559 Player::handle_input()
560 {
561   /* Handle horizontal movement: */
562     handle_horizontal_input();
563
564   /* Jump/jumping? */
565
566   if (on_ground() && input.up == UP)
567     can_jump = true;
568   handle_vertical_input();
569
570   /* Shoot! */
571   if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER)
572     {
573       if(Sector::current()->add_bullet(Vector(base.x, base.y + (base.height/2)),
574           physic.get_velocity_x(), dir))
575         shooting_timer.start(SHOOTING_TIME);
576       input.old_fire = DOWN;
577     }
578
579   /* tux animations: */
580   if(!frame_timer.check())
581     {
582       frame_timer.start(25);
583       if (input.right == UP && input.left == UP)
584         {
585           frame_main = 1;
586           frame_ = 1;
587         }
588       else
589         {
590           if ((input.fire == DOWN && (global_frame_counter % 2) == 0) ||
591               (global_frame_counter % 4) == 0)
592             frame_main = (frame_main + 1) % 4;
593
594           frame_ = frame_main;
595
596           if (frame_ == 3)
597             frame_ = 1;
598         }
599     }
600
601   /* Duck! */
602   if (input.down == DOWN && size == BIG && !duck && physic.get_velocity_y() == 0 && on_ground())
603     {
604       duck = true;
605       base.height = 32;                             
606       base.y += 32;
607       // changing base size confuses collision otherwise
608       old_base = previous_base = base;
609     }
610   else if(input.down == UP && size == BIG && duck)
611     {
612       // try if we can really unduck
613       base.y -= 32;
614       base.height = 64;
615       // when unducking in air we need some space to do so
616       if(on_ground() || !collision_object_map(base)) {
617         duck = false;
618         // changing base size confuses collision otherwise
619         old_base = previous_base = base;                                
620       } else {
621         // undo the ducking changes
622         base.y += 32;
623         base.height = 32;
624       }   
625     }
626 }
627
628 void
629 Player::grow(bool animate)
630 {
631   if(size == BIG)
632     return;
633   
634   size = BIG;
635   base.height = 64;
636   base.y -= 32;
637
638   if(animate)
639     growing_timer.start(GROWING_TIME);
640
641   old_base = previous_base = base;
642 }
643
644 void
645 Player::grabdistros()
646 {
647   /* Grab distros: */
648   if (!dying)
649     {
650       Sector::current()->trygrabdistro(Vector(base.x, base.y), NO_BOUNCE);
651       Sector::current()->trygrabdistro(Vector(base.x+ 31, base.y), NO_BOUNCE);
652
653       Sector::current()->trygrabdistro(
654           Vector(base.x, base.y + base.height), NO_BOUNCE);
655       Sector::current()->trygrabdistro(
656           Vector(base.x+ 31, base.y + base.height), NO_BOUNCE);
657
658       if(size == BIG)
659         {
660           Sector::current()->trygrabdistro(
661               Vector(base.x, base.y + base.height / 2), NO_BOUNCE);
662           Sector::current()->trygrabdistro(
663               Vector(base.x+ 31, base.y + base.height / 2), NO_BOUNCE);
664         }
665
666     }
667
668   /* Enough distros for a One-up? */
669   if (player_status.distros >= DISTROS_LIFEUP)
670     {
671       player_status.distros = player_status.distros - DISTROS_LIFEUP;
672       if(player_status.lives < MAX_LIVES)
673         ++player_status.lives;
674       /*We want to hear the sound even, if MAX_LIVES is reached*/
675       sound_manager->play_sound(sounds[SND_LIFEUP]);
676     }
677 }
678
679 void
680 Player::draw(DrawingContext& context)
681 {
682   PlayerSprite* sprite;
683           
684   if (size == SMALL)
685     sprite = &smalltux;
686   else if (got_power == FIRE_POWER)
687     sprite = &firetux;
688   else if (got_power == ICE_POWER)
689     sprite = &icetux;
690   else
691     sprite = &largetux;
692
693   int layer = LAYER_OBJECTS - 1;
694   Vector pos = Vector(base.x, base.y);
695
696   if (!safe_timer.started() || (global_frame_counter % 2) == 0)
697     {
698       if (dying == DYING_SQUISHED)
699         {
700           smalltux_gameover->draw(context, pos, LAYER_OBJECTS+1);
701         }
702       else
703         {
704           if(growing_timer.check())
705             {
706               if (dir == RIGHT)
707                 context.draw_surface(growingtux_right[(growing_timer.get_gone() * GROWING_FRAMES) / GROWING_TIME], pos, layer);
708               else 
709                 context.draw_surface(growingtux_left[(growing_timer.get_gone() * GROWING_FRAMES) / GROWING_TIME], pos, layer);
710             }
711           else if (duck && size != SMALL)
712             {
713               if (dir == RIGHT)
714                 sprite->duck_right->draw(context, pos, layer);
715               else 
716                 sprite->duck_left->draw(context, pos, layer);
717             }
718           else if (skidding_timer.started())
719             {
720               if (dir == RIGHT)
721                 sprite->skid_right->draw(context, pos, layer);
722               else
723                 sprite->skid_left->draw(context, pos, layer);
724             }
725           else if (kick_timer.started())
726             {
727               if (dir == RIGHT)
728                 sprite->kick_right->draw(context, pos, layer);
729               else
730                 sprite->kick_left->draw(context, pos, layer);
731             }
732           else if (physic.get_velocity_y() != 0)
733             {
734               if (dir == RIGHT)
735                 sprite->jump_right->draw(context, pos, layer);
736               else
737                 sprite->jump_left->draw(context, pos, layer);
738             }
739           else
740             {
741               if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
742                 {
743                   if (dir == RIGHT)
744                     sprite->stand_right->draw(context, pos, layer);
745                   else
746                     sprite->stand_left->draw(context, pos, layer);
747                 }
748               else // moving
749                 {
750                   if (dir == RIGHT)
751                     sprite->walk_right->draw(context, pos, layer);
752                   else
753                     sprite->walk_left->draw(context, pos, layer);
754                 }
755             }
756         }
757     }     
758
759   // Draw arm overlay graphics when Tux is holding something
760   if ((holding_something && physic.get_velocity_y() == 0) || shooting_timer.check() && !duck)
761   {
762     if (dir == RIGHT)
763       sprite->grab_right->draw(context, pos, LAYER_OBJECTS + 1);
764     else
765       sprite->grab_left->draw(context, pos, LAYER_OBJECTS + 1);
766   }
767
768   // Draw blinking star overlay
769   if (invincible_timer.started() &&
770       (invincible_timer.get_left() > TUX_INVINCIBLE_TIME_WARNING || global_frame_counter % 3))
771   {
772     if (size == SMALL || duck)
773       smalltux_star->draw(context, pos, LAYER_OBJECTS + 2);
774     else
775       largetux_star->draw(context, pos, LAYER_OBJECTS + 2);
776   }
777  
778   if (debug_mode)
779     context.draw_filled_rect(Vector(base.x, base.y),
780         Vector(base.width, base.height), Color(75,75,75, 150), LAYER_OBJECTS+1);
781 }
782
783 void
784 Player::collision(const MovingObject& other, int collision_type)
785 {
786   (void) other;
787   (void) collision_type;
788   // will be implemented later
789 }
790
791 void
792 Player::collision(void* p_c_object, int c_object)
793 {
794   BadGuy* pbad_c = NULL;
795   Trampoline* ptramp_c = NULL;
796   FlyingPlatform* pplatform_c = NULL;
797
798   switch (c_object)
799     {
800     case CO_BADGUY:
801       pbad_c = (BadGuy*) p_c_object;
802
803      /* Hurt player if he touches a badguy */
804       if (!pbad_c->dying && !dying &&
805           !safe_timer.started() &&
806           pbad_c->mode != BadGuy::HELD)
807         {
808           if (pbad_c->mode == BadGuy::FLAT && input.fire == DOWN
809                && !holding_something)
810             {
811               holding_something = true;
812               pbad_c->mode = BadGuy::HELD;
813               pbad_c->base.y-=8;
814             }
815           else if (pbad_c->mode == BadGuy::FLAT)
816             {
817               // Don't get hurt if we're kicking a flat badguy!
818             }
819           else if (pbad_c->mode == BadGuy::KICK)
820             {
821               /* Hurt if you get hit by kicked laptop: */
822               if (!invincible_timer.started())
823                 {
824                   kill(SHRINK);
825                 }
826               else
827                 pbad_c->kill_me(20);
828             }
829           else if (pbad_c->frozen_timer.check() && (pbad_c->kind == BAD_MRBOMB
830               || pbad_c->kind == BAD_JUMPY || pbad_c->kind == BAD_FISH
831               || pbad_c->kind == BAD_SPIKY))
832                 pbad_c->kill_me(20);
833           else
834             {
835               if (!invincible_timer.started())
836                 {
837                   kill(SHRINK);
838                 }
839               else
840                 {
841                   pbad_c->kill_me(25);
842                 }
843             }
844           player_status.score_multiplier++;
845         }
846       break;
847
848     case CO_TRAMPOLINE:
849       ptramp_c = (Trampoline*) p_c_object;
850       
851       // Pick up trampoline
852       if (ptramp_c->mode != Trampoline::M_HELD && input.fire == DOWN && !holding_something && on_ground())
853       {
854         holding_something = true;
855         ptramp_c->mode = Trampoline::M_HELD;
856         ptramp_c->base.y -= 8;
857       }
858       // Set down trampoline
859       else if (ptramp_c->mode == Trampoline::M_HELD && input.fire != DOWN)
860       {
861         holding_something = false;
862         ptramp_c->mode = Trampoline::M_NORMAL;
863         ptramp_c->base.y += 8;
864         ptramp_c->physic.set_velocity(physic.get_velocity_x(), physic.get_velocity_y());
865
866         //if (dir == RIGHT)
867         //  ptramp_c->base.x = base.x + base.width+1;
868         //else /* LEFT */
869         //  ptramp_c->base.x = base.x - base.width-1;
870       }
871 /*
872       // Don't let tux walk through trampoline
873       else if (ptramp_c->mode != Trampoline::M_HELD && on_ground())
874       {
875         if (physic.get_velocity_x() > 0) // RIGHT
876         {
877           physic.set_velocity_x(0);
878           base.x = ptramp_c->base.x - base.width;
879         }
880         else if (physic.get_velocity_x() < 0) // LEFT
881         {
882           physic.set_velocity_x(0);
883           base.x = ptramp_c->base.x + ptramp_c->base.width;
884         }
885       }
886 */
887       break;
888     case CO_FLYING_PLATFORM:
889       pplatform_c = (FlyingPlatform*) p_c_object;
890       
891       base.y = pplatform_c->base.y - base.height;
892       physic.set_velocity_x(pplatform_c->get_vel_x());
893       
894       physic.enable_gravity(false);
895       can_jump = true;
896       fall_mode = ON_GROUND;
897       break;
898
899     default:
900       break;
901     }
902
903 }
904
905 /* Kill Player! */
906
907 void
908 Player::kill(HurtMode mode)
909 {
910   if(dying)
911     return;
912   
913   sound_manager->play_sound(sounds[SND_HURT]);
914
915   physic.set_velocity_x(0);
916
917   if (mode == SHRINK && size == BIG)
918     {
919       if (got_power != NONE_POWER)
920         {
921           got_power = NONE_POWER;
922         }
923       else
924         {
925           size = SMALL;
926           base.height = 32;
927           duck = false;
928         }
929       safe_timer.start(TUX_SAFE_TIME);
930     }
931   else
932     {
933       physic.enable_gravity(true);
934       physic.set_acceleration(0, 0);
935       physic.set_velocity(0, 7);
936       --player_status.lives;
937       dying = DYING_SQUISHED;
938       dying_timer.start(3000);
939     }
940 }
941
942 /* Remove Tux's power ups */
943 void
944 Player::remove_powerups()
945 {
946   got_power = NONE_POWER;
947   size = SMALL;
948   base.height = 32;
949 }
950
951 void
952 Player::move(const Vector& vector)
953 {
954   base.x = vector.x;
955   base.y = vector.y;
956   old_base = previous_base = base;
957 }
958
959 void
960 Player::check_bounds(Camera* camera)
961 {
962   /* Keep tux in bounds: */
963   if (base.x < 0)
964     { // Lock Tux to the size of the level, so that he doesn't fall of
965       // on the left side
966       base.x = 0;
967     }
968
969   /* Keep in-bounds, vertically: */
970   if (base.y > Sector::current()->solids->get_height() * 32)
971     {
972       kill(KILL);
973       return;
974     }
975
976   bool adjust = false;
977   // can happen if back scrolling is disabled
978   if(base.x < camera->get_translation().x) {
979     base.x = camera->get_translation().x;
980     adjust = true;
981   }
982   if(base.x >= camera->get_translation().x + screen->w - base.width) {
983     base.x = camera->get_translation().x + screen->w - base.width;
984     adjust = true;
985   }
986
987   if(adjust) {
988     // squished now?
989     if(collision_object_map(base)) {
990       kill(KILL);
991       return;
992     }
993   }
994 }
995