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