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