fix from Tron so player doesn't get hurt by eggs
[supertux.git] / src / object / player.cpp
index a80ea94..df2ca01 100644 (file)
@@ -108,10 +108,10 @@ TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer)
     feet->draw(context, pos, layer-2);
 }
 
-Player::Player(PlayerStatus* _player_status, std::string name) :
-  MovingObject(name), player_status(_player_status), grabbed_object(NULL),
-  ghost_mode(false)
+Player::Player(PlayerStatus* _player_status, const std::string& name)
+  : player_status(_player_status), grabbed_object(NULL), ghost_mode(false)
 {
+  this->name = name;
   controller = main_controller;
   smalltux_gameover = sprite_manager->create("images/creatures/tux_small/smalltux-gameover.sprite");
   smalltux_star = sprite_manager->create("images/creatures/tux_small/smalltux-star.sprite");
@@ -171,14 +171,18 @@ Player::init()
 void
 Player::expose(HSQUIRRELVM vm, SQInteger table_idx)
 {
-  if (name.empty()) return;
+  if (name.empty())
+    return;
+
   Scripting::expose_object(vm, table_idx, dynamic_cast<Scripting::Player *>(this), name, false);
 }
 
 void
 Player::unexpose(HSQUIRRELVM vm, SQInteger table_idx)
 {
-  if (name.empty()) return;
+  if (name.empty())
+    return;
+
   Scripting::unexpose_object(vm, table_idx, name);
 }
 
@@ -198,7 +202,7 @@ Player::adjust_height(float new_height)
   if(new_height > bbox.get_height()) {
     Rect additional_space = bbox2;
     additional_space.set_height(new_height - bbox.get_height());
-    if(!Sector::current()->is_free_space(additional_space))
+    if(!Sector::current()->is_free_of_statics(additional_space, this))
       return false;
   }
 
@@ -226,7 +230,10 @@ Player::update(float elapsed_time)
     handle_input();
 
   // handle_input() calls apply_friction() when Tux is not walking, so we'll have to do this ourselves
-  if (deactivated) apply_friction();
+  if (deactivated)
+    apply_friction();
+
+  try_grab = false;
 
   // extend/shrink tux collision rectangle so that we fall through/walk over 1
   // tile holes
@@ -547,7 +554,8 @@ Player::handle_vertical_input()
   // swimming
   physic.set_acceleration_y(0);
   if (swimming) {
-    if (controller->hold(Controller::UP) || controller->hold(Controller::JUMP)) physic.set_acceleration_y(-2000);
+    if (controller->hold(Controller::UP) || controller->hold(Controller::JUMP))
+      physic.set_acceleration_y(-2000);
     physic.set_velocity_y(physic.get_velocity_y() * 0.94);
   }
 }
@@ -555,29 +563,13 @@ Player::handle_vertical_input()
 void
 Player::handle_input()
 {
+  Sector* sector = Sector::current();
+  
   if (ghost_mode) {
     handle_input_ghost();
     return;
   }
 
-  if(!controller->hold(Controller::ACTION) && grabbed_object) {
-    // move the grabbed object a bit away from tux
-    Vector pos = get_pos() +
-        Vector(dir == LEFT ? -bbox.get_width()-1 : bbox.get_width()+1,
-                bbox.get_height()*0.66666 - 32);
-    Rect dest(pos, pos + Vector(32, 32));
-    if(Sector::current()->is_free_space(dest)) {
-      MovingObject* moving_object = dynamic_cast<MovingObject*> (grabbed_object);
-      if(moving_object) {
-        moving_object->set_pos(pos);
-      } else {
-        log_debug << "Non MovingObjetc grabbed?!?" << std::endl;
-      }
-      grabbed_object->ungrab(*this, dir);
-      grabbed_object = NULL;
-    }
-  }
-
   /* Peeking */
   if( controller->released( Controller::PEEK_LEFT ) ) {
     peeking = AUTO;
@@ -612,8 +604,58 @@ Player::handle_input()
   }
 
   /* Duck or Standup! */
-  if (controller->hold(Controller::DOWN)) do_duck(); else do_standup();
+  if (controller->hold(Controller::DOWN)) {
+    do_duck();
+  } else {
+    do_standup();
+  }
 
+  /* grabbing */
+  if(controller->hold(Controller::ACTION) && !grabbed_object
+      && try_grab && !duck) {
+    Vector pos;
+    if(grab_dir == LEFT) {
+      pos = Vector(bbox.get_left() - 5, bbox.get_bottom() - 16);
+    } else {
+      pos = Vector(bbox.get_right() + 5, bbox.get_bottom() - 16);
+    }
+
+    for(Sector::Portables::iterator i = sector->portables.begin();
+        i != sector->portables.end(); ++i) {
+      Portable* portable = *i;
+      if(!portable->is_portable())
+        continue;
+
+      MovingObject* moving_object = dynamic_cast<MovingObject*> (portable);
+      assert(portable);
+      if(moving_object == NULL)
+        continue;
+
+      if(moving_object->get_bbox().contains(pos)) {
+        grabbed_object = portable;
+        grabbed_object->grab(*this, get_pos(), dir);
+        break;
+      }
+    }
+  }
+
+  if(!controller->hold(Controller::ACTION) && grabbed_object) {
+    // move the grabbed object a bit away from tux
+    Vector pos = get_pos() +
+        Vector(dir == LEFT ? -bbox.get_width()-1 : bbox.get_width()+1,
+                bbox.get_height()*0.66666 - 32);
+    Rect dest(pos, pos + Vector(32, 32));
+    if(Sector::current()->is_free_of_statics(dest)) {
+      MovingObject* moving_object = dynamic_cast<MovingObject*> (grabbed_object);
+      if(moving_object) {
+        moving_object->set_pos(pos);
+      } else {
+        log_debug << "Non MovingObjetc grabbed?!?" << std::endl;
+      }
+      grabbed_object->ungrab(*this, dir);
+      grabbed_object = NULL;
+    }
+  }
 }
 
 void
@@ -913,6 +955,8 @@ Player::collision_solid(const CollisionHit& hit)
 
   if(hit.left || hit.right) {
     physic.set_velocity_x(0);
+    try_grab = true;
+    grab_dir = hit.left ? LEFT : RIGHT;
   }
 
   // crushed?
@@ -926,21 +970,13 @@ Player::collision_solid(const CollisionHit& hit)
 }
 
 HitResponse
-Player::collision(GameObject& other, const CollisionHit& hit)
+Player::collision(GameObject& other, const CollisionHit& )
 {
   Bullet* bullet = dynamic_cast<Bullet*> (&other);
   if(bullet) {
     return FORCE_MOVE;
   }
 
-  // if we hit something from the side that is portable, the ACTION button is pressed and we are not already holding anything: grab it
-  Portable* portable = dynamic_cast<Portable*> (&other);
-  if ((hit.left || hit.right) && (portable && portable->is_portable()) && controller->hold(Controller::ACTION) && (!grabbed_object)) {
-    grabbed_object = portable;
-    grabbed_object->grab(*this, get_pos(), dir);
-    return CONTINUE;
-  }
-
 #ifdef DEBUG
   assert(dynamic_cast<MovingObject*> (&other) != NULL);
 #endif