-optimized and cleaned up collision_object_map
[supertux.git] / src / player.cpp
index baedf12..afc4eb5 100644 (file)
 #include "screen.h"
 
 Surface* tux_life;
-std::vector<Surface*> tux_right;
-std::vector<Surface*> tux_left;
-Surface* smalltux_jump_left;
-Surface* smalltux_jump_right;
-Surface* smalltux_stand_left;
-Surface* smalltux_stand_right;
-
-Sprite* bigtux_right;
-Sprite* bigtux_left;
-Sprite* bigtux_right_jump;
-Sprite* bigtux_left_jump;
-Sprite* ducktux_right;
-Sprite* ducktux_left;
-Surface* skidtux_right;
-Surface* skidtux_left;
-Surface* firetux_right[3];
-Surface* firetux_left[3];
-Surface* bigfiretux_right[3];
-Surface* bigfiretux_left[3];
-Surface* bigfiretux_right_jump;
-Surface* bigfiretux_left_jump;
-Surface* duckfiretux_right;
-Surface* duckfiretux_left;
-Surface* skidfiretux_right;
-Surface* skidfiretux_left;
-Surface* cape_right[2];
-Surface* cape_left[2];
-Surface* bigcape_right[2];
-Surface* bigcape_left[2];
+
+Sprite* smalltux_gameover;
+Sprite* smalltux_star;
+Sprite* largetux_star;
+
+PlayerSprite smalltux;
+PlayerSprite largetux;
+PlayerSprite firetux;
 
 PlayerKeymap keymap;
 
@@ -85,6 +64,8 @@ Player::init()
 {
   Level* plevel = World::current()->get_level();
 
+  holding_something = false;
+
   base.width = 32;
   base.height = 32;
 
@@ -111,6 +92,7 @@ Player::init()
   skidding_timer.init(true);
   safe_timer.init(true);
   frame_timer.init(true);
+  kick_timer.init(true);
 
   physic.reset();
 }
@@ -140,6 +122,8 @@ Player::key_event(SDLKey key, int state)
     }
   else if(key == keymap.fire)
     {
+      if (state == UP)
+        input.old_fire = UP;
       input.fire = state;
       return true;
     }
@@ -174,15 +158,18 @@ Player::action(double frame_ratio)
 {
   bool jumped_in_solid = false;
 
-  /* --- HANDLE TUX! --- */
-
-  if(dying == DYING_NOT)
-    handle_input();
+  if (input.fire == UP)
+    holding_something = false;
 
   /* Move tux: */
   previous_base = base;
 
+  /* --- HANDLE TUX! --- */
+  if(dying == DYING_NOT)
+    handle_input();
+
   physic.apply(frame_ratio, base.x, base.y);
+
   if(dying == DYING_NOT) 
     {
       base_type target = base;
@@ -198,19 +185,15 @@ Player::action(double frame_ratio)
       // special exception for cases where we're stuck under tiles after
       // being ducked. In this case we drift out
       if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
-         && collision_object_map(&base)) {
-        base.x += frame_ratio * WALK_SPEED * (dir ? 1 : -1);
-        previous_base = old_base = base;
-      }
+         && collision_object_map(base))
+        {
+          base.x += frame_ratio * WALK_SPEED * (dir ? 1 : -1);
+          previous_base = old_base = base;
+        }
       keep_in_bounds();
-    }
-
-  if (dying == DYING_NOT)
-    {
-      /* Land: */
 
-
-      if!on_ground())
+      // Land:
+      if (!on_ground())
         {
           physic.enable_gravity(true);
           if(under_solid())
@@ -276,40 +259,13 @@ Player::action(double frame_ratio)
         }
     }
 
-
   /* ---- DONE HANDLING TUX! --- */
 
-  /* Handle invincibility timer: */
-  if (get_current_music() == HERRING_MUSIC && !invincible_timer.check())
-    {
-      /*
-        no, we are no more invincible
-        or we were not in invincible mode
-        but are we in hurry ?
-      */
-
-      // FIXME: Move this to gamesession
-      if (GameSession::current()->time_left.get_left() < TIME_WARNING)
-        {
-          /* yes, we are in hurry
-             stop the herring_song, prepare to play the correct
-             fast level_song !
-          */
-          set_current_music(HURRYUP_MUSIC);
-        }
-      else
-        {
-          set_current_music(LEVEL_MUSIC);
-        }
-
-      /* start playing it */
-      play_current_music();
-    }
-
   // check some timers
   skidding_timer.check();
   invincible_timer.check();
   safe_timer.check();
+  kick_timer.check();
 }
 
 bool
@@ -415,11 +371,11 @@ Player::handle_horizontal_input()
 void
 Player::handle_vertical_input()
 {
-  if(input.up == DOWN)
+  if(input.up == DOWN && input.old_up == UP)
     {
       if (on_ground())
         {
-          // jump
+          // jump higher if we are running
           if (physic.get_velocity_x() > MAX_WALK_XM)
             physic.set_velocity_y(5.8);
           else
@@ -454,12 +410,14 @@ Player::handle_input()
     {
       handle_vertical_input();
     }
+  input.old_up = input.up;
 
   /* Shoot! */
 
   if (input.fire == DOWN && input.old_fire == UP && got_coffee)
     {
       World::current()->add_bullet(base.x, base.y, physic.get_velocity_x(), dir);
+      input.old_fire = DOWN;
     }
 
   /* tux animations: */
@@ -485,7 +443,7 @@ Player::handle_input()
     }
 
   /* Duck! */
-  if (input.down == DOWN && size == BIG && !duck && physic.get_velocity_y() == 0)
+  if (input.down == DOWN && size == BIG && !duck && physic.get_velocity_y() == 0 && on_ground())
     {
       duck = true;
       base.height = 32;                             
@@ -493,16 +451,30 @@ Player::handle_input()
       // changing base size confuses collision otherwise
       old_base = previous_base = base;
     }
-  else if(input.down == UP && size == BIG && duck && physic.get_velocity_y() == 0)
+  else if(input.down == UP && size == BIG && duck && physic.get_velocity_y() == 0 && on_ground())
     {
       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: */
@@ -538,155 +510,90 @@ Player::draw()
 {
   if (!safe_timer.started() || (global_frame_counter % 2) == 0)
     {
-      if (size == SMALL)
+      if (dying == DYING_SQUISHED)
         {
-          if (invincible_timer.started())
+          smalltux_gameover->draw(base.x - scroll_x, base.y);
+        }
+      else
+        {
+          PlayerSprite* sprite;
+          
+          if (size == SMALL)
+            sprite = &smalltux;
+          else if (got_coffee)
+            sprite = &firetux;
+          else
+            sprite = &largetux;
+          
+          if (duck && size != SMALL)
             {
-              /* Draw cape: */
-
               if (dir == RIGHT)
-                cape_right[global_frame_counter % 2]->draw(base.x- scroll_x, base.y);
-              else
-                cape_left[global_frame_counter % 2]->draw(base.x- scroll_x, base.y);
+                sprite->duck_right->draw(base.x - scroll_x, base.y);
+              else 
+                sprite->duck_left->draw(base.x - scroll_x, base.y);
             }
-
-
-          if (!got_coffee)
+          else if (skidding_timer.started())
             {
-              if (physic.get_velocity_y() != 0)
-                {
-                  if (dir == RIGHT)
-                    smalltux_jump_right->draw( base.x - scroll_x, base.y - 10);
-                  else
-                    smalltux_jump_left->draw( base.x - scroll_x, base.y - 10);                   
-                }
+              if (dir == RIGHT)
+                sprite->skid_right->draw(base.x - scroll_x, base.y);
               else
-                {
-                  if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
-                    {
-                      if (dir == RIGHT)
-                        smalltux_stand_right->draw( base.x - scroll_x, base.y - 9);
-                      else
-                        smalltux_stand_left->draw( base.x - scroll_x, base.y - 9);
-                    }
-                  else // moving
-                    {
-                      if (dir == RIGHT)
-                        tux_right[(global_frame_counter/2) % tux_right.size()]->draw(base.x - scroll_x, base.y - 9);
-                      else
-                        tux_left[(global_frame_counter/2) % tux_left.size()]->draw(base.x - scroll_x, base.y - 9);
-                    }
-                }
+                sprite->skid_left->draw(base.x - scroll_x, base.y); 
             }
-          else
+          else if (kick_timer.started())
             {
-              /* Tux got coffee! */
-
               if (dir == RIGHT)
-                {
-                  firetux_right[frame_]->draw( base.x- scroll_x, base.y);
-                }
+                sprite->kick_right->draw(base.x - scroll_x, base.y);
               else
-                {
-                  firetux_left[frame_]->draw( base.x- scroll_x, base.y);
-                }
+                sprite->kick_left->draw(base.x - scroll_x, base.y); 
             }
-        }
-      else
-        {
-          if (invincible_timer.started())
+          else if (physic.get_velocity_y() != 0)
             {
-              float capex = base.x + (base.width - bigcape_right[0]->w) / 2;
-              capex -= scroll_x;
-              float capey = base.y + (base.height - bigcape_right[0]->h) / 2;
-                
-              /* Draw cape (just not in ducked mode since that looks silly): */
               if (dir == RIGHT)
-                bigcape_right[global_frame_counter % 2]->draw(capex, capey);
+                sprite->jump_right->draw(base.x - scroll_x, base.y);
               else
-                bigcape_left[global_frame_counter % 2]->draw(capex, capey);
+                sprite->jump_left->draw(base.x - scroll_x, base.y);                   
             }
-
-          if (!got_coffee)
+          else
             {
-              if (!duck)
+              if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
                 {
-                  if (!skidding_timer.started())
-                    {
-                      if (physic.get_velocity_y() == 0)
-                        {
-                          if (dir == RIGHT)
-                            bigtux_right->draw(base.x - scroll_x, base.y);
-                          else
-                            bigtux_left->draw(base.x - scroll_x, base.y);
-                        }
-                      else
-                        {
-                          if (dir == RIGHT)
-                            bigtux_right_jump->draw(base.x - scroll_x, base.y);
-                          else
-                            bigtux_left_jump->draw(base.x - scroll_x, base.y);
-                        }
-                    }
+                  if (dir == RIGHT)
+                    sprite->stand_right->draw( base.x - scroll_x, base.y);
                   else
-                    {
-                      if (dir == RIGHT)
-                        skidtux_right->draw(base.x - scroll_x - 8, base.y);
-                      else
-                        skidtux_left->draw(base.x - scroll_x - 8, base.y);
-                    }
+                    sprite->stand_left->draw( base.x - scroll_x, base.y);
                 }
-              else
+              else // moving
                 {
                   if (dir == RIGHT)
-                    ducktux_right->draw(base.x - scroll_x, base.y);
+                    sprite->walk_right->draw(base.x - scroll_x, base.y);
                   else
-                    ducktux_left->draw(base.x - scroll_x, base.y);
+                    sprite->walk_left->draw(base.x - scroll_x, base.y);
                 }
             }
-          else
+                      
+          // Draw arm overlay graphics when Tux is holding something
+          if (holding_something && physic.get_velocity_y() == 0)
             {
-              /* Tux has coffee! */
-              if (!duck)
-                {
-                  if (!skidding_timer.started())
-                    {
-                      if (!jumping || physic.get_velocity_y() > 0)
-                        {
-                          if (dir == RIGHT)
-                            bigfiretux_right[frame_]->draw(base.x- scroll_x - 8, base.y);
-                          else
-                            bigfiretux_left[frame_]->draw(base.x- scroll_x - 8, base.y);
-                        }
-                      else
-                        {
-                          if (dir == RIGHT)
-                            bigfiretux_right_jump->draw(base.x- scroll_x - 8, base.y);
-                          else
-                            bigfiretux_left_jump->draw(base.x- scroll_x - 8, base.y);
-                        }
-                    }
-                  else
-                    {
-                      if (dir == RIGHT)
-                        skidfiretux_right->draw(base.x- scroll_x - 8, base.y);
-                      else
-                        skidfiretux_left->draw(base.x- scroll_x - 8, base.y);
-                    }
-                }
+              if (dir == RIGHT)
+                sprite->grab_right->draw(base.x - scroll_x, base.y);
               else
-                {
-                  if (dir == RIGHT)
-                    duckfiretux_right->draw( base.x- scroll_x - 8, base.y - 16);
-                  else
-                    duckfiretux_left->draw( base.x- scroll_x - 8, base.y - 16);
-                }
+                sprite->grab_left->draw(base.x - scroll_x, base.y);
             }
-        }
-    }
 
+          // Draw blinking star overlay
+          if (invincible_timer.started())
+            {
+              if (size == SMALL || duck)
+                smalltux_star->draw(base.x - scroll_x, base.y);
+              else
+                largetux_star->draw(base.x - scroll_x, base.y);
+            }
+        }
+    }     
+  
   if (debug_mode)
-    fillrect(base.x - scroll_x, base.y, 32, 32, 75,75,75, 150);
+    fillrect(base.x - scroll_x, base.y, 
+             base.width, base.height, 75,75,75, 150);
 }
 
 void
@@ -702,18 +609,20 @@ Player::collision(void* p_c_object, int c_object)
      /* Hurt player if he touches a badguy */
       if (!pbad_c->dying && !dying &&
           !safe_timer.started() &&
-          pbad_c->mode != HELD)
+          pbad_c->mode != BadGuy::HELD)
         {
-          if (pbad_c->mode == FLAT && input.fire == DOWN)
+          if (pbad_c->mode == BadGuy::FLAT && input.fire == DOWN
+               && !holding_something)
             {
-              pbad_c->mode = HELD;
+              holding_something = true;
+              pbad_c->mode = BadGuy::HELD;
               pbad_c->base.y-=8;
             }
-          else if (pbad_c->mode == FLAT)
+          else if (pbad_c->mode == BadGuy::FLAT)
             {
               // Don't get hurt if we're kicking a flat badguy!
             }
-          else if (pbad_c->mode == KICK)
+          else if (pbad_c->mode == BadGuy::KICK)
             {
               /* Hurt if you get hit by kicked laptop: */
               if (!invincible_timer.started())
@@ -737,7 +646,7 @@ Player::collision(void* p_c_object, int c_object)
                 }
               else
                 {
-                  pbad_c->kill_me();
+                  pbad_c->kill_me(25);
                 }
             }
           player_status.score_multiplier++;
@@ -752,21 +661,24 @@ Player::collision(void* p_c_object, int c_object)
 /* Kill Player! */
 
 void
-Player::kill(int mode)
+Player::kill(HurtMode mode)
 {
   play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
 
-  physic.set_velocity(0, physic.get_velocity_y());
+  physic.set_velocity_x(0);
 
   if (mode == SHRINK && size == BIG)
     {
       if (got_coffee)
-        got_coffee = false;
-
-      size = SMALL;
-      base.height = 32;
-      duck = false;
-
+        {
+          got_coffee = false;
+        }
+      else
+        {
+          size = SMALL;
+          base.height = 32;
+          duck = false;
+        }
       safe_timer.start(TUX_SAFE_TIME);
     }
   else