Tux can peek to the left and to the right as far as the camera would move in best...
[supertux.git] / src / object / player.cpp
index 5104012..4aab47f 100644 (file)
@@ -48,6 +48,7 @@
 #include "log.hpp"
 #include "falling_coin.hpp"
 #include "random_generator.hpp"
+#include "object/sprite_particle.hpp"
 
 static const int TILES_FOR_BUTTJUMP = 3;
 static const float SHOOTING_TIME = .150;
@@ -116,6 +117,8 @@ Player::Player(PlayerStatus* _player_status)
   sound_manager->preload("sounds/jump.wav");
   sound_manager->preload("sounds/hurt.wav");
   sound_manager->preload("sounds/skid.wav");
+  sound_manager->preload("sounds/flip.wav");
+  sound_manager->preload("sounds/invincible.wav");
 
   init();
 }
@@ -141,6 +144,7 @@ Player::init()
   dead = false;
 
   dying = false;
+  peeking = AUTO;
   last_ground_y = 0;
   fall_mode = ON_GROUND;
   jumping = false;
@@ -228,7 +232,7 @@ Player::update(float elapsed_time)
   if (backflipping) {
     //prevent player from changing direction when backflipping 
     dir = (backflip_direction == 1) ? LEFT : RIGHT; 
-    if (backflip_timer.check()) physic.set_velocity_x(100 * backflip_direction);
+    if (backflip_timer.started()) physic.set_velocity_x(100 * backflip_direction);
   }
 
   // set fall mode...
@@ -309,6 +313,30 @@ Player::update(float elapsed_time)
   }
 
   on_ground_flag = false;
+
+  // when invincible, spawn particles
+  if (invincible_timer.started() && !dying)
+  {
+    if (systemRandom.rand(0, 2) == 0) {
+      float px = systemRandom.randf(bbox.p1.x+0, bbox.p2.x-0);
+      float py = systemRandom.randf(bbox.p1.y+0, bbox.p2.y-0);
+      Vector ppos = Vector(px, py);
+      Vector pspeed = Vector(0, 0);
+      Vector paccel = Vector(0, 0);
+      // draw bright sparkle when there is lots of time left, dark sparkle when invincibility is about to end
+      if (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING) {
+       // make every other a longer sparkle to make trail a bit fuzzy
+       if (size_t(game_time*20)%2) {
+         Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "small", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
+       } else {
+         Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "medium", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
+       }
+      } else {
+        Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "dark", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
+      }
+    }
+  } 
+
 }
 
 bool
@@ -484,9 +512,13 @@ Player::do_backflip() {
   if (!duck) return;
   if (!on_ground()) return;
 
+  // TODO: we don't have an animation for firetux backflipping, so let's revert to bigtux
+  set_bonus(GROWUP_BONUS, true);
+
   backflip_direction = (dir == LEFT)?(+1):(-1);
   backflipping = true;
   do_jump(-580);
+  sound_manager->play("sounds/flip.wav");
   backflip_timer.start(0.15);
 }
 
@@ -583,6 +615,20 @@ Player::handle_input()
       grabbed_object = NULL;
     }
   }
+
+  /* Peeking */
+  if( controller->released( Controller::PEEK_LEFT ) ) {
+    peeking = AUTO;
+  } 
+  if( controller->released( Controller::PEEK_RIGHT ) ) {
+    peeking = AUTO;
+  }
+  if( controller->pressed( Controller::PEEK_LEFT ) ) {
+    peeking = LEFT;
+  } 
+  if( controller->pressed( Controller::PEEK_RIGHT ) ) {
+    peeking = RIGHT;
+  }
  
   /* Handle horizontal movement: */
   if (!backflipping) handle_horizontal_input();
@@ -686,6 +732,14 @@ Player::set_bonus(BonusType type, bool animate)
   }
 
   if ((type == NO_BONUS) || (type == GROWUP_BONUS)) {
+    if ((player_status->bonus == FIRE_BONUS) && (animate)) {
+      // visually lose helmet
+      Vector ppos = Vector((bbox.p1.x + bbox.p2.x) / 2, bbox.p1.y);
+      Vector pspeed = Vector(((dir==LEFT) ? +100 : -100), -300);
+      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));
+    }
     player_status->max_fire_bullets = 0;
     player_status->max_ice_bullets = 0;
   }
@@ -699,6 +753,10 @@ void
 Player::set_visible(bool visible)
 {
   this->visible = visible;
+  if( visible ) 
+    set_group(COLGROUP_MOVING);
+  else
+    set_group(COLGROUP_DISABLED);
 }
 
 bool
@@ -843,17 +901,6 @@ Player::draw(DrawingContext& context)
   else
     tux_body->draw(context, get_pos(), layer);
 
-  // Draw blinking star overlay
-  if (invincible_timer.started() &&
-     (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING
-      || size_t(game_time*20)%2)
-     && !dying)
-  {
-    if (!is_big() || duck)
-      smalltux_star->draw(context, get_pos(), layer + 5);
-    else
-      bigtux_star->draw(context, get_pos(), layer + 5);
-  } 
 }
 
 void
@@ -987,7 +1034,7 @@ Player::kill(bool completely)
   if(dying || deactivated)
     return;
 
-  if(!completely && safe_timer.started() || invincible_timer.started())
+  if(!completely && (safe_timer.started() || invincible_timer.started()))
     return;                          
   
   sound_manager->play("sounds/hurt.wav");
@@ -998,13 +1045,13 @@ Player::kill(bool completely)
     if(player_status->bonus == FIRE_BONUS
         || player_status->bonus == ICE_BONUS) {
       safe_timer.start(TUX_SAFE_TIME);
-      set_bonus(GROWUP_BONUS);
+      set_bonus(GROWUP_BONUS, true);
     } else {
       //growing_timer.start(GROWING_TIME);
       safe_timer.start(TUX_SAFE_TIME /* + GROWING_TIME */);
       adjust_height(30.8);
       duck = false;
-      set_bonus(NO_BONUS);
+      set_bonus(NO_BONUS, true);
     }
   } else {
     for (int i = 0; (i < 5) && (i < player_status->coins); i++)
@@ -1018,7 +1065,7 @@ Player::kill(bool completely)
     physic.set_acceleration(0, 0);
     physic.set_velocity(0, -700);
     player_status->coins -= 25;
-    set_bonus(NO_BONUS);
+    set_bonus(NO_BONUS, true);
     dying = true;
     dying_timer.start(3.0);
     set_group(COLGROUP_DISABLED);