Fixed creating level-subset again.
[supertux.git] / src / player.cpp
index 82fe8a5..179b533 100644 (file)
@@ -18,7 +18,6 @@
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include <math.h>
-
 #include "gameloop.h"
 #include "globals.h"
 #include "player.h"
@@ -28,6 +27,8 @@
 #include "sprite.h"
 #include "screen.h"
 
+#define AUTOSCROLL_DEAD_INTERVAL 300
+
 Surface* tux_life;
 
 Sprite* smalltux_gameover;
@@ -57,6 +58,7 @@ void player_input_init(player_input_type* pplayer_input)
   pplayer_input->old_fire = UP;
   pplayer_input->right = UP;
   pplayer_input->up = UP;
+  pplayer_input->old_up = UP;
 }
 
 void
@@ -78,10 +80,12 @@ Player::init()
   base.ym = 0;
   previous_base = old_base = base;
   dir = RIGHT;
+  old_dir = dir;
   duck = false;
 
   dying   = DYING_NOT;
   jumping = false;
+  can_jump = true;
 
   frame_main = 0;
   frame_ = 0;
@@ -190,7 +194,7 @@ Player::action(double frame_ratio)
           base.x += frame_ratio * WALK_SPEED * (dir ? 1 : -1);
           previous_base = old_base = base;
         }
-      keep_in_bounds();
+      check_bounds();
 
       // Land:
       if (!on_ground())
@@ -294,9 +298,11 @@ Player::handle_horizontal_input()
 
   float dirsign = 0;
   if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
+      old_dir = dir;
       dir = LEFT;
       dirsign = -1;
   } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
+      old_dir = dir;
       dir = RIGHT;
       dirsign = 1;
   }
@@ -371,24 +377,27 @@ Player::handle_horizontal_input()
 void
 Player::handle_vertical_input()
 {
-  if(input.up == DOWN)
+  // Press jump key
+  if(input.up == DOWN && can_jump)
     {
       if (on_ground())
         {
           // jump higher if we are running
-          if (physic.get_velocity_x() > MAX_WALK_XM)
+          if (fabs(physic.get_velocity_x()) > MAX_WALK_XM)
             physic.set_velocity_y(5.8);
           else
             physic.set_velocity_y(5.2);
 
           --base.y;
           jumping = true;
+          can_jump = false;
           if (size == SMALL)
             play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
           else
             play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
         }
     }
+  // Let go of jump key
   else if(input.up == UP && jumping)
     {
       jumping = false;
@@ -396,6 +405,19 @@ Player::handle_vertical_input()
         physic.set_velocity_y(0);
       }
     }
+
+  if ( (issolid(base.x + base.width / 2, base.y + base.height + 64) ||
+        issolid(base.x + 1, base.y + base.height + 64) ||
+        issolid(base.x + base.width - 1, base.y + base.height + 64))
+       && jumping  == false
+       && can_jump == false
+       && input.up == DOWN
+       && input.old_up == UP)
+    {
+      can_jump = true;
+    }
+
+  input.old_up = input.up;
 }
 
 void
@@ -406,7 +428,9 @@ Player::handle_input()
 
   /* Jump/jumping? */
 
-  if ( input.up == DOWN || (input.up == UP && jumping))
+  if (on_ground() && input.up == UP)
+    can_jump = true;
+  if (input.up == DOWN || (input.up == UP && jumping))
     {
       handle_vertical_input();
     }
@@ -455,11 +479,25 @@ Player::handle_input()
       duck = false;
       base.y -= 32;
       base.height = 64;
-      old_base = previous_base = base;
+      // changing base size confuses collision otherwise
+      old_base = previous_base = base;                        
     }
 }
 
 void
+Player::grow()
+{
+  if(size == BIG)
+    return;
+  
+  size = BIG;
+  base.height = 64;
+  base.y -= 32;
+
+  old_base = previous_base = base;
+}
+
+void
 Player::grabdistros()
 {
   /* Grab distros: */
@@ -510,13 +548,13 @@ Player::draw()
           else
             sprite = &largetux;
           
-          if (duck)
+          if (duck && size != SMALL)
             {
               if (dir == RIGHT)
                 sprite->duck_right->draw(base.x - scroll_x, base.y);
               else 
                 sprite->duck_left->draw(base.x - scroll_x, base.y);
-            }                    
+            }
           else if (skidding_timer.started())
             {
               if (dir == RIGHT)
@@ -566,7 +604,8 @@ Player::draw()
             }
 
           // Draw blinking star overlay
-          if (invincible_timer.started())
+          if (invincible_timer.started() &&
+             (invincible_timer.get_left() > TUX_INVINCIBLE_TIME_WARNING || global_frame_counter % 3))
             {
               if (size == SMALL || duck)
                 smalltux_star->draw(base.x - scroll_x, base.y);
@@ -596,7 +635,8 @@ Player::collision(void* p_c_object, int c_object)
           !safe_timer.started() &&
           pbad_c->mode != BadGuy::HELD)
         {
-          if (pbad_c->mode == BadGuy::FLAT && input.fire == DOWN)
+          if (pbad_c->mode == BadGuy::FLAT && input.fire == DOWN
+               && !holding_something)
             {
               holding_something = true;
               pbad_c->mode = BadGuy::HELD;
@@ -630,7 +670,7 @@ Player::collision(void* p_c_object, int c_object)
                 }
               else
                 {
-                  pbad_c->kill_me();
+                  pbad_c->kill_me(25);
                 }
             }
           player_status.score_multiplier++;
@@ -683,7 +723,7 @@ Player::is_dying()
 
 bool Player::is_dead()
 {
-  if(base.y > screen->h)
+  if(base.y > screen->h || base.x < scroll_x - AUTOSCROLL_DEAD_INTERVAL)  // last condition can happen in auto-scrolling
     return true;
   else
     return false;
@@ -699,20 +739,14 @@ Player::remove_powerups()
 }
 
 void
-Player::keep_in_bounds()
+Player::check_bounds()
 {
-  Level* plevel = World::current()->get_level();
-
   /* Keep tux in bounds: */
   if (base.x < 0)
     { // Lock Tux to the size of the level, so that he doesn't fall of
       // on the left side
       base.x = 0;
     }
-  else if (base.x < scroll_x)
-    { 
-      base.x = scroll_x;
-    }
 
   /* Keep in-bounds, vertically: */
   if (base.y > screen->h)
@@ -720,37 +754,17 @@ Player::keep_in_bounds()
       kill(KILL);
     }
 
-  int scroll_threshold = screen->w/2 - 80;
-  if (debug_mode)
-    {
-      scroll_x += screen->w/2;
-      // Backscrolling for debug mode
-      if (scroll_x < base.x - 80)
-        scroll_x = base.x - 80;
-      else if (scroll_x > base.x + 80)
-        scroll_x = base.x + 80;
-      scroll_x -= screen->w/2;
-
-      if(scroll_x < 0)
-        scroll_x = 0;
-    }
-  else
-    {
-      if (base.x > scroll_threshold + scroll_x
-          && scroll_x < ((World::current()->get_level()->width * 32) - screen->w))
-        {
-          // FIXME: Scrolling needs to be handled by a seperate View
-          // class, doing it as a player huck is ugly
-          
-          // Scroll the screen in past center:
-          scroll_x = base.x - scroll_threshold;
-          
-          // Lock the scrolling to the levelsize, so that we don't
-          // scroll over the right border
-          if (scroll_x > 32 * plevel->width - screen->w)
-            scroll_x = 32 * plevel->width - screen->w;
-        }
-    }
+  if(base.x < scroll_x)  // can happen if back scrolling is disabled
+    base.x = scroll_x;
+
+  if(base.x == scroll_x)
+    if(issolid(base.x, base.y) || issolid(base.x, base.y+32))
+      kill(KILL);
+
+  if(base.x + base.width > scroll_x + screen->w)
+    base.x = scroll_x + screen->w - base.width;
+
+    
 }
 
 // EOF //