converted player to new object system
[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);
70   init();
71 }
72
73 Player::~Player()
74 {
75 }
76
77 void
78 Player::init()
79 {
80   Level* plevel = World::current()->get_level();
81
82   holding_something = false;
83
84   base.width = 32;
85   base.height = 32;
86
87   size = SMALL;
88   got_power = NONE_POWER;
89
90   base.x = plevel->start_pos_x;
91   base.y = plevel->start_pos_y;
92   base.xm = 0;
93   base.ym = 0;
94   previous_base = old_base = base;
95   dir = RIGHT;
96   old_dir = dir;
97   duck = false;
98
99   dying   = DYING_NOT;
100   jumping = false;
101   can_jump = true;
102   butt_jump = false;
103
104   frame_main = 0;
105   frame_ = 0;
106   
107   player_input_init(&input);
108
109   invincible_timer.init(true);
110   skidding_timer.init(true);
111   safe_timer.init(true);
112   frame_timer.init(true);
113   kick_timer.init(true);
114
115   physic.reset();
116 }
117
118 int
119 Player::key_event(SDLKey key, int state)
120 {
121   if(key == keymap.right)
122     {
123       input.right = state;
124       return true;
125     }
126   else if(key == keymap.left)
127     {
128       input.left = state;
129       return true;
130     }
131   else if(key == keymap.jump)
132     {
133       input.up = state;
134       return true;
135     }
136   else if(key == keymap.duck)
137     {
138       input.down = state;
139       return true;
140     }
141   else if(key == keymap.fire)
142     {
143       if (state == UP)
144         input.old_fire = UP;
145       input.fire = state;
146       return true;
147     }
148   else
149     return false;
150 }
151
152 void
153 Player::level_begin()
154 {
155   base.x  = 100;
156   base.y  = 170;
157   base.xm = 0;
158   base.ym = 0;
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       holding_something = true;
481       World::current()->add_bullet(base.x, base.y + (base.height/2), physic.get_velocity_x(), dir);
482       input.old_fire = DOWN;
483     }
484
485   /* tux animations: */
486   if(!frame_timer.check())
487     {
488       frame_timer.start(25);
489       if (input.right == UP && input.left == UP)
490         {
491           frame_main = 1;
492           frame_ = 1;
493         }
494       else
495         {
496           if ((input.fire == DOWN && (global_frame_counter % 2) == 0) ||
497               (global_frame_counter % 4) == 0)
498             frame_main = (frame_main + 1) % 4;
499
500           frame_ = frame_main;
501
502           if (frame_ == 3)
503             frame_ = 1;
504         }
505     }
506
507   /* Duck! */
508   if (input.down == DOWN && size == BIG && !duck && physic.get_velocity_y() == 0 && on_ground())
509     {
510       duck = true;
511       base.height = 32;                             
512       base.y += 32;
513       // changing base size confuses collision otherwise
514       old_base = previous_base = base;
515     }
516   else if(input.down == UP && size == BIG && duck)
517     {
518       // try if we can really unduck
519       base.y -= 32;
520       base.height = 64;
521       // when unducking in air we need some space to do so
522       if(on_ground() || !collision_object_map(base)) {
523         duck = false;
524         // changing base size confuses collision otherwise
525         old_base = previous_base = base;                                
526       } else {
527         // undo the ducking changes
528         base.y += 32;
529         base.height = 32;
530       }   
531     }
532 }
533
534 void
535 Player::grow()
536 {
537   if(size == BIG)
538     return;
539   
540   size = BIG;
541   base.height = 64;
542   base.y -= 32;
543
544   old_base = previous_base = base;
545 }
546
547 void
548 Player::grabdistros()
549 {
550   /* Grab distros: */
551   if (!dying)
552     {
553       World::current()->trygrabdistro(base.x, base.y, NO_BOUNCE);
554       World::current()->trygrabdistro(base.x+ 31, base.y, NO_BOUNCE);
555
556       World::current()->trygrabdistro(base.x, base.y + base.height, NO_BOUNCE);
557       World::current()->trygrabdistro(base.x+ 31, base.y + base.height, NO_BOUNCE);
558
559       if(size == BIG)
560         {
561           World::current()->trygrabdistro(base.x, base.y + base.height / 2, NO_BOUNCE);
562           World::current()->trygrabdistro(base.x+ 31, base.y + base.height / 2, NO_BOUNCE);
563         }
564
565     }
566
567   /* Enough distros for a One-up? */
568   if (player_status.distros >= DISTROS_LIFEUP)
569     {
570       player_status.distros = player_status.distros - DISTROS_LIFEUP;
571       if(player_status.lives < MAX_LIVES)
572         ++player_status.lives;
573       /*We want to hear the sound even, if MAX_LIVES is reached*/
574       play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
575     }
576 }
577
578 void
579 Player::draw(ViewPort& viewport, int )
580 {
581   float scroll_x = viewport.get_translation().x;
582   float scroll_y = viewport.get_translation().y;
583
584   if (!safe_timer.started() || (global_frame_counter % 2) == 0)
585     {
586       if (dying == DYING_SQUISHED)
587         {
588           smalltux_gameover->draw(base.x, base.y);
589         }
590       else
591         {
592           PlayerSprite* sprite;
593           
594           if (size == SMALL)
595             sprite = &smalltux;
596           else if (got_power == FIRE_POWER)
597             sprite = &firetux;
598           else if (got_power == ICE_POWER)
599             sprite = &icetux;
600           else
601             sprite = &largetux;
602           
603           if (duck && size != SMALL)
604             {
605               if (dir == RIGHT)
606                 sprite->duck_right->draw(base.x, base.y);
607               else 
608                 sprite->duck_left->draw(base.x, base.y);
609             }
610           else if (skidding_timer.started())
611             {
612               if (dir == RIGHT)
613                 sprite->skid_right->draw(base.x, base.y);
614               else
615                 sprite->skid_left->draw(base.x, base.y); 
616             }
617           else if (kick_timer.started())
618             {
619               if (dir == RIGHT)
620                 sprite->kick_right->draw(base.x, base.y);
621               else
622                 sprite->kick_left->draw(base.x, base.y); 
623             }
624           else if (physic.get_velocity_y() != 0)
625             {
626               if (dir == RIGHT)
627                 sprite->jump_right->draw(base.x, base.y);
628               else
629                 sprite->jump_left->draw(base.x, base.y);                   
630             }
631           else
632             {
633               if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
634                 {
635                   if (dir == RIGHT)
636                     sprite->stand_right->draw( base.x, base.y);
637                   else
638                     sprite->stand_left->draw( base.x, base.y);
639                 }
640               else // moving
641                 {
642                   if (dir == RIGHT)
643                     sprite->walk_right->draw(base.x, base.y);
644                   else
645                     sprite->walk_left->draw(base.x, base.y);
646                 }
647             }
648                       
649           // Draw arm overlay graphics when Tux is holding something
650           if (holding_something && physic.get_velocity_y() == 0)
651             {
652               if (dir == RIGHT)
653                 sprite->grab_right->draw(base.x, base.y);
654               else
655                 sprite->grab_left->draw(base.x, base.y);
656             }
657
658           // Draw blinking star overlay
659           if (invincible_timer.started() &&
660              (invincible_timer.get_left() > TUX_INVINCIBLE_TIME_WARNING || global_frame_counter % 3))
661             {
662               if (size == SMALL || duck)
663                 smalltux_star->draw(base.x, base.y);
664               else
665                 largetux_star->draw(base.x, base.y);
666             }
667         }
668     }     
669   
670   if (debug_mode)
671     fillrect(base.x - scroll_x, base.y - scroll_y, 
672              base.width, base.height, 75,75,75, 150);
673 }
674
675 void
676 Player::collision(const MovingObject& other, int collision_type)
677 {
678   (void) other;
679   (void) collision_type;
680   // will be implemented later
681 }
682
683 void
684 Player::collision(void* p_c_object, int c_object)
685 {
686   BadGuy* pbad_c = NULL;
687   Trampoline* ptramp_c = NULL;
688
689   switch (c_object)
690     {
691     case CO_BADGUY:
692       pbad_c = (BadGuy*) p_c_object;
693
694      /* Hurt player if he touches a badguy */
695       if (!pbad_c->dying && !dying &&
696           !safe_timer.started() &&
697           pbad_c->mode != BadGuy::HELD)
698         {
699           if (pbad_c->mode == BadGuy::FLAT && input.fire == DOWN
700                && !holding_something)
701             {
702               holding_something = true;
703               pbad_c->mode = BadGuy::HELD;
704               pbad_c->base.y-=8;
705             }
706           else if (pbad_c->mode == BadGuy::FLAT)
707             {
708               // Don't get hurt if we're kicking a flat badguy!
709             }
710           else if (pbad_c->mode == BadGuy::KICK)
711             {
712               /* Hurt if you get hit by kicked laptop: */
713               if (!invincible_timer.started())
714                 {
715                   kill(SHRINK);
716                 }
717               else
718                 pbad_c->kill_me(20);
719             }
720           else if (pbad_c->frozen_timer.check() && (pbad_c->kind == BAD_MRBOMB
721               || pbad_c->kind == BAD_JUMPY || pbad_c->kind == BAD_FISH
722               || pbad_c->kind == BAD_SPIKY))
723                 pbad_c->kill_me(20);
724           else
725             {
726               if (!invincible_timer.started())
727                 {
728                   kill(SHRINK);
729                 }
730               else
731                 {
732                   pbad_c->kill_me(25);
733                 }
734             }
735           player_status.score_multiplier++;
736         }
737       break;
738
739     case CO_TRAMPOLINE:
740       ptramp_c = (Trampoline*) p_c_object;
741       
742       // Pick up trampoline
743       if (ptramp_c->mode != Trampoline::M_HELD && input.fire == DOWN && !holding_something && on_ground())
744       {
745         holding_something = true;
746         ptramp_c->mode = Trampoline::M_HELD;
747         ptramp_c->base.y -= 8;
748       }
749       // Set down trampoline
750       else if (ptramp_c->mode == Trampoline::M_HELD && input.fire != DOWN)
751       {
752         holding_something = false;
753         ptramp_c->mode = Trampoline::M_NORMAL;
754         ptramp_c->base.y += 8;
755         ptramp_c->physic.set_velocity(physic.get_velocity_x(), physic.get_velocity_y());
756
757         //if (dir == RIGHT)
758         //  ptramp_c->base.x = base.x + base.width+1;
759         //else /* LEFT */
760         //  ptramp_c->base.x = base.x - base.width-1;
761       }
762 /*
763       // Don't let tux walk through trampoline
764       else if (ptramp_c->mode != Trampoline::M_HELD && on_ground())
765       {
766         if (physic.get_velocity_x() > 0) // RIGHT
767         {
768           physic.set_velocity_x(0);
769           base.x = ptramp_c->base.x - base.width;
770         }
771         else if (physic.get_velocity_x() < 0) // LEFT
772         {
773           physic.set_velocity_x(0);
774           base.x = ptramp_c->base.x + ptramp_c->base.width;
775         }
776       }
777 */
778
779       break;
780
781     default:
782       break;
783     }
784
785 }
786
787 /* Kill Player! */
788
789 void
790 Player::kill(HurtMode mode)
791 {
792   play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
793
794   physic.set_velocity_x(0);
795
796   if (mode == SHRINK && size == BIG)
797     {
798       if (got_power != NONE_POWER)
799         {
800           got_power = NONE_POWER;
801         }
802       else
803         {
804           size = SMALL;
805           base.height = 32;
806           duck = false;
807         }
808       safe_timer.start(TUX_SAFE_TIME);
809     }
810   else
811     {
812       physic.enable_gravity(true);
813       physic.set_acceleration(0, 0);
814       physic.set_velocity(0, 7);
815       if(dying != DYING_SQUISHED)
816       --player_status.lives;
817       dying = DYING_SQUISHED;
818     }
819 }
820
821 void
822 Player::is_dying()
823 {
824   remove_powerups();
825   dying = DYING_NOT;
826 }
827
828 bool Player::is_dead()
829 {
830   if(base.y > screen->h + scroll_y || base.y > World::current()->get_level()->height*32 ||
831       base.x < scroll_x - AUTOSCROLL_DEAD_INTERVAL)  // can happen in auto-scrolling
832     return true;
833   else
834     return false;
835 }
836
837 /* Remove Tux's power ups */
838 void
839 Player::remove_powerups()
840 {
841   got_power = NONE_POWER;
842   size = SMALL;
843   base.height = 32;
844 }
845
846 void
847 Player::check_bounds(bool back_scrolling, bool hor_autoscroll)
848 {
849   /* Keep tux in bounds: */
850   if (base.x < 0)
851     { // Lock Tux to the size of the level, so that he doesn't fall of
852       // on the left side
853       base.x = 0;
854     }
855
856   /* Keep in-bounds, vertically: */
857   if (base.y > World::current()->get_level()->height * /*TILE_HEIGHT*/ 32)
858     {
859       kill(KILL);
860     }
861
862   if(base.x < scroll_x && (!back_scrolling || hor_autoscroll))  // can happen if back scrolling is disabled
863     base.x = scroll_x;
864
865   if(hor_autoscroll)
866     {
867     if(base.x == scroll_x)
868       if(issolid(base.x+32, base.y) || (size != SMALL && issolid(base.x+32, base.y+32)))
869         kill(KILL);
870
871     if(base.x + base.width > scroll_x + screen->w)
872       base.x = scroll_x + screen->w - base.width;
873     }
874     
875 }
876
877 // EOF //
878