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