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