- Use obstacks for memory allocation for lispfiles and DrawingRequests,
[supertux.git] / src / object / player.cpp
index bcde741..d070c29 100644 (file)
 #include "falling_coin.hpp"
 #include "random_generator.hpp"
 #include "object/sprite_particle.hpp"
+#include "trigger/climbable.hpp"
 
 static const int TILES_FOR_BUTTJUMP = 3;
 static const float SHOOTING_TIME = .150f;
 /// time before idle animation starts
 static const float IDLE_TIME = 2.5f;
 
+/** acceleration in horizontal direction when walking
+ * (all acceleratiosn are in  pixel/s^2) */
 static const float WALK_ACCELERATION_X = 300;
+/** acceleration in horizontal direction when running */ 
 static const float RUN_ACCELERATION_X = 400;
+/** acceleration when skidding */
 static const float SKID_XM = 200;
+/** time of skidding in seconds */
 static const float SKID_TIME = .3f;
+/** maximum walk velocity (pixel/s) */
 static const float MAX_WALK_XM = 230;
+/** maximum run velcoity (pixel/s) */
 static const float MAX_RUN_XM = 320;
+/** maximum horizontal climb velocity */
+static const float MAX_CLIMB_XM = 48;
+/** maximum vertical climb velocity */
+static const float MAX_CLIMB_YM = 128;
+/** instant velocity when tux starts to walk */
 static const float WALK_SPEED = 100;
 
+/** time of the kick (kicking mriceblock) animation */
 static const float KICK_TIME = .3f;
+/** time of tux cheering (currently unused) */
 static const float CHEER_TIME = 1.0f;
 
-static const float UNDUCK_HURT_TIME = 0.25f; /**< if Tux cannot unduck for this long, he will get hurt */
+/** if Tux cannot unduck for this long, he will get hurt */
+static const float UNDUCK_HURT_TIME = 0.25f;
 
 // growing animation
 Surface* growingtux_left[GROWING_FRAMES];
@@ -109,7 +125,7 @@ TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer)
 }
 
 Player::Player(PlayerStatus* _player_status, const std::string& name)
-  : player_status(_player_status), grabbed_object(NULL), ghost_mode(false)
+  : player_status(_player_status), grabbed_object(NULL), ghost_mode(false), climbing(0)
 {
   this->name = name;
   controller = main_controller;
@@ -126,12 +142,12 @@ Player::Player(PlayerStatus* _player_status, const std::string& name)
   sound_manager->preload("sounds/invincible.wav");
   sound_manager->preload("sounds/splash.ogg");
 
-
   init();
 }
 
 Player::~Player()
 {
+  if (climbing) stop_climbing(*climbing);
   delete smalltux_gameover;
   delete smalltux_star;
   delete bigtux_star;
@@ -167,6 +183,8 @@ Player::init()
   on_ground_flag = false;
   grabbed_object = NULL;
 
+  climbing = 0;
+
   physic.reset();
 }
 
@@ -216,7 +234,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_of_statics(additional_space, this))
+    if(!Sector::current()->is_free_of_statics(additional_space, this, true))
       return false;
   }
 
@@ -230,6 +248,7 @@ Player::adjust_height(float new_height)
 void
 Player::trigger_sequence(std::string sequence_name)
 {
+  if (climbing) stop_climbing(*climbing);
   GameSession::current()->start_sequence(sequence_name);
 }
 
@@ -596,6 +615,10 @@ Player::handle_input()
     handle_input_ghost();
     return;
   }
+  if (climbing) {
+    handle_input_climbing();
+    return;
+  }
 
   /* Peeking */
   if( controller->released( Controller::PEEK_LEFT ) ) {
@@ -684,6 +707,7 @@ Player::try_grab()
         continue;
 
       if(moving_object->get_bbox().contains(pos)) {
+        if (climbing) stop_climbing(*climbing);
         grabbed_object = portable;
         grabbed_object->grab(*this, get_pos(), dir);
         break;
@@ -783,6 +807,7 @@ Player::set_bonus(BonusType type, bool animate)
     }
     if(animate)
       growing_timer.start(GROWING_TIME);
+    if (climbing) stop_climbing(*climbing);
   }
 
   if ((type == NO_BONUS) || (type == GROWUP_BONUS)) {
@@ -793,6 +818,7 @@ Player::set_bonus(BonusType type, bool animate)
       Vector paccel = Vector(0, 1000);
       std::string action = (dir==LEFT)?"left":"right";
       Sector::current()->add_object(new SpriteParticle("images/objects/particles/firetux-helmet.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
+      if (climbing) stop_climbing(*climbing);
     }
     if ((player_status->bonus == ICE_BONUS) && (animate)) {
       // visually lose cap
@@ -801,6 +827,7 @@ Player::set_bonus(BonusType type, bool animate)
       Vector paccel = Vector(0, 1000);
       std::string action = (dir==LEFT)?"left":"right";
       Sector::current()->add_object(new SpriteParticle("images/objects/particles/icetux-cap.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
+      if (climbing) stop_climbing(*climbing);
     }
     player_status->max_fire_bullets = 0;
     player_status->max_ice_bullets = 0;
@@ -862,7 +889,11 @@ Player::draw(DrawingContext& context)
   int layer = LAYER_OBJECTS + 1;
 
   /* Set Tux sprite action */
-  if (backflipping)
+  if (climbing)
+    {
+    tux_body->set_action("skid-left");
+    }
+  else if (backflipping)
     {
     if(dir == LEFT)
       tux_body->set_action("backflip-left");
@@ -1078,6 +1109,7 @@ Player::kill(bool completely)
     return;
 
   sound_manager->play("sounds/hurt.wav");
+  if (climbing) stop_climbing(*climbing);
 
   physic.set_velocity_x(0);
 
@@ -1099,17 +1131,24 @@ Player::kill(bool completely)
       duck = false;
     }
   } else {
-    for (int i = 0; (i < 5) && (i < player_status->coins); i++)
+    if (player_status->coins >= 25 && !GameSession::current()->get_reset_point_sectorname().empty())
     {
-      // the numbers: starting x, starting y, velocity y
-      Sector::current()->add_object(new FallingCoin(get_pos() +
-            Vector(systemRandom.rand(5), systemRandom.rand(-32,18)),
-            systemRandom.rand(-100,100)));
+      for (int i = 0; i < 5; i++)
+      {
+        // the numbers: starting x, starting y, velocity y
+        Sector::current()->add_object(new FallingCoin(get_pos() +
+              Vector(systemRandom.rand(5), systemRandom.rand(-32,18)),
+              systemRandom.rand(-100,100)));
+      }
+      player_status->coins -= std::max(player_status->coins/10, 25);
+    }
+    else
+    {
+      GameSession::current()->set_reset_point("", Vector());
     }
     physic.enable_gravity(true);
     physic.set_acceleration(0, 0);
     physic.set_velocity(0, -700);
-    player_status->coins -= 25;
     set_bonus(NO_BONUS, true);
     dying = true;
     dying_timer.start(3.0);
@@ -1134,6 +1173,7 @@ Player::move(const Vector& vector)
     set_size(31.8f, 31.8f);
   duck = false;
   last_ground_y = vector.y;
+  if (climbing) stop_climbing(*climbing);
 
   physic.reset();
 }
@@ -1206,6 +1246,7 @@ Player::deactivate()
   physic.set_velocity_y(0);
   physic.set_acceleration_x(0);
   physic.set_acceleration_y(0);
+  if (climbing) stop_climbing(*climbing);
 }
 
 void
@@ -1227,6 +1268,8 @@ Player::set_ghost_mode(bool enable)
   if (ghost_mode == enable)
     return;
 
+  if (climbing) stop_climbing(*climbing);
+
   if (enable) {
     ghost_mode = true;
     set_group(COLGROUP_DISABLED);
@@ -1239,3 +1282,80 @@ Player::set_ghost_mode(bool enable)
     log_debug << "You feel solid again." << std::endl;
   }
 }
+
+
+void 
+Player::start_climbing(Climbable& climbable)
+{
+  if (climbing == &climbable) return;
+
+  climbing = &climbable;
+  physic.enable_gravity(false);
+  physic.set_velocity(0, 0);
+  physic.set_acceleration(0, 0);
+}
+
+void 
+Player::stop_climbing(Climbable& /*climbable*/)
+{
+  if (!climbing) return;
+
+  climbing = 0;
+
+  if (grabbed_object) {    
+    grabbed_object->ungrab(*this, dir);
+    grabbed_object = NULL;
+  }
+
+  physic.enable_gravity(true);
+  physic.set_velocity(0, 0);
+  physic.set_acceleration(0, 0);
+
+  if ((controller->hold(Controller::JUMP)) || (controller->hold(Controller::UP))) {
+    on_ground_flag = true;
+    // TODO: This won't help. Why?
+    do_jump(-300);
+  }
+}
+
+void
+Player::handle_input_climbing()
+{
+  if (!climbing) {
+    log_warning << "handle_input_climbing called with climbing set to 0. Input handling skipped" << std::endl;
+    return;
+  }
+
+  float vx = 0;
+  float vy = 0;
+  if (controller->hold(Controller::LEFT)) {
+    dir = LEFT;
+    vx -= MAX_CLIMB_XM;
+  }
+  if (controller->hold(Controller::RIGHT)) {
+    dir = RIGHT;
+    vx += MAX_CLIMB_XM;
+  }
+  if (controller->hold(Controller::UP)) {
+    vy -= MAX_CLIMB_YM;
+  }
+  if (controller->hold(Controller::DOWN)) {
+    vy += MAX_CLIMB_YM;
+  }
+  if (controller->hold(Controller::JUMP)) {
+    if (can_jump) {
+      stop_climbing(*climbing);
+      return;
+    }  
+  } else {
+    can_jump = true;
+  }
+  if (controller->hold(Controller::ACTION)) {
+    stop_climbing(*climbing);
+    return;
+  }
+  physic.set_velocity(vx, vy);
+  physic.set_acceleration(0, 0);
+}
+
+