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