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