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