src/object/icecrusher.cpp

Go to the documentation of this file.
00001 //  IceCrusher - A block to stand on, which can drop down to crush the player
00002 //  Copyright (C) 2008 Christoph Sommer <christoph.sommer@2008.expires.deltadevelopment.de>
00003 //  Copyright (C) 2010 Florian Forster <supertux at octo.it>
00004 //
00005 //  This program is free software: you can redistribute it and/or modify
00006 //  it under the terms of the GNU General Public License as published by
00007 //  the Free Software Foundation, either version 3 of the License, or
00008 //  (at your option) any later version.
00009 //
00010 //  This program is distributed in the hope that it will be useful,
00011 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 //  GNU General Public License for more details.
00014 //
00015 //  You should have received a copy of the GNU General Public License
00016 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 #include "object/icecrusher.hpp"
00019 
00020 #include "badguy/badguy.hpp"
00021 #include "sprite/sprite.hpp"
00022 #include "object/player.hpp"
00023 #include "object/camera.hpp"
00024 #include "supertux/object_factory.hpp"
00025 #include "supertux/sector.hpp"
00026 
00027 namespace {
00028 /* Maximum movement speed in pixels per LOGICAL_FPS */
00029 const float MAX_DROP_SPEED = 10.0;
00030 const float RECOVER_SPEED_NORMAL = -3.125;
00031 const float RECOVER_SPEED_LARGE  = -2.0;
00032 const float DROP_ACTIVATION_DISTANCE = 4.0;
00033 const float PAUSE_TIME_NORMAL = 0.5;
00034 const float PAUSE_TIME_LARGE  = 1.0;
00035 }
00036 
00037 IceCrusher::IceCrusher(const Reader& reader) :
00038   MovingSprite(reader, "images/creatures/icecrusher/icecrusher.sprite", LAYER_OBJECTS, COLGROUP_STATIC), 
00039   state(IDLE), 
00040   start_position(),
00041   physic(),
00042   cooldown_timer(0.0),
00043   ic_size(NORMAL)
00044 {
00045   start_position = get_bbox().p1;
00046   set_state(state, true);
00047   
00048   float sprite_width = sprite->get_width ();
00049   if (sprite_width >= 128.0)
00050     ic_size = LARGE;
00051 }
00052 
00053 /*
00054   IceCrusher::IceCrusher(const IceCrusher& other)
00055   : MovingSprite(other), 
00056   state(other.state), speed(other.speed) 
00057   {
00058   start_position = get_bbox().p1;
00059   set_state(state, true);
00060   }
00061 */
00062 void 
00063 IceCrusher::set_state(IceCrusherState state, bool force) 
00064 {
00065   if ((this->state == state) && (!force)) return;
00066   switch(state) {
00067     case IDLE:
00068       set_group(COLGROUP_STATIC);
00069       physic.enable_gravity (false);
00070       sprite->set_action("idle");
00071       break;
00072     case CRUSHING:
00073       set_group(COLGROUP_MOVING_STATIC);
00074       physic.reset ();
00075       physic.enable_gravity (true);
00076       sprite->set_action("crushing");
00077       break;
00078     case RECOVERING:
00079       set_group(COLGROUP_MOVING_STATIC);
00080       physic.enable_gravity (false);
00081       sprite->set_action("recovering");
00082       break;
00083     default:
00084       log_debug << "IceCrusher in invalid state" << std::endl;
00085       break;
00086   }
00087   this->state = state;
00088 }
00089 
00090 HitResponse
00091 IceCrusher::collision(GameObject& other, const CollisionHit& hit)
00092 {
00093   Player* player = dynamic_cast<Player*>(&other);
00094 
00095   /* If the other object is the player, and the collision is at the bottom of
00096    * the ice crusher, hurt the player. */
00097   if (player && hit.bottom) {
00098     if(player->is_invincible()) {
00099       if (state == CRUSHING)
00100         set_state(RECOVERING);
00101       return ABORT_MOVE;
00102     }
00103     player->kill(false);
00104     if (state == CRUSHING)
00105       set_state(RECOVERING);
00106     return FORCE_MOVE;
00107   }
00108   BadGuy* badguy = dynamic_cast<BadGuy*>(&other);
00109   if (badguy) {
00110     badguy->kill_fall();
00111   }
00112   return FORCE_MOVE;
00113 }
00114     
00115 void 
00116 IceCrusher::collision_solid(const CollisionHit& hit)
00117 {
00118   switch(state) {
00119     case IDLE:
00120       break;
00121     case CRUSHING:
00122       if (hit.bottom) {
00123         if (ic_size == LARGE) {
00124           cooldown_timer = PAUSE_TIME_LARGE;
00125           Sector::current()->camera->shake (/* frequency = */ .125f, /* x = */ 0.0, /* y = */ 16.0);
00126         }
00127         else {
00128           cooldown_timer = PAUSE_TIME_NORMAL;
00129           Sector::current()->camera->shake (/* frequency = */ .1f, /* x = */ 0.0, /* y = */ 8.0);
00130         }
00131         set_state(RECOVERING);
00132       }
00133       break;
00134     case RECOVERING:
00135       break;
00136     default:
00137       log_debug << "IceCrusher in invalid state" << std::endl;
00138       break;
00139   }
00140 }
00141 
00142 void
00143 IceCrusher::update(float elapsed_time)
00144 {
00145   if (cooldown_timer >= elapsed_time)
00146   {
00147     cooldown_timer -= elapsed_time;
00148     return;
00149   }
00150   else if (cooldown_timer != 0.0)
00151   {
00152     elapsed_time -= cooldown_timer;
00153     cooldown_timer = 0.0;
00154   }
00155 
00156   switch(state) {
00157     case IDLE:
00158       movement = Vector (0, 0);
00159       if (found_victim())
00160         set_state(CRUSHING);
00161       break;
00162     case CRUSHING:
00163       movement = physic.get_movement (elapsed_time);
00164       if (movement.y > MAX_DROP_SPEED)
00165         movement.y = MAX_DROP_SPEED;
00166       break;
00167     case RECOVERING:
00168       if (get_bbox().p1.y <= start_position.y+1) {
00169         set_pos(start_position);
00170         movement = Vector (0, 0);
00171         if (ic_size == LARGE)
00172           cooldown_timer = PAUSE_TIME_LARGE;
00173         else
00174           cooldown_timer = PAUSE_TIME_NORMAL;
00175         set_state(IDLE);
00176       }
00177       else {
00178         if (ic_size == LARGE)
00179           movement = Vector (0, RECOVER_SPEED_LARGE);
00180         else
00181           movement = Vector (0, RECOVER_SPEED_NORMAL);
00182       }
00183       break;
00184     default:
00185       log_debug << "IceCrusher in invalid state" << std::endl;
00186       break;
00187   }
00188 }
00189 
00190 bool
00191 IceCrusher::found_victim()
00192 {
00193   Player* player = Sector::current()->get_nearest_player (this->get_bbox ());
00194   if (!player) return false;
00195 
00196   const Rectf& player_bbox = player->get_bbox();
00197   const Rectf& crusher_bbox = get_bbox();
00198   if ((player_bbox.p1.y >= crusher_bbox.p2.y) /* player is below crusher */
00199       && (player_bbox.p2.x > (crusher_bbox.p1.x - DROP_ACTIVATION_DISTANCE))
00200       && (player_bbox.p1.x < (crusher_bbox.p2.x + DROP_ACTIVATION_DISTANCE)))
00201     return true;
00202   else
00203     return false;
00204 }
00205 
00206 /* EOF */

Generated on Mon Jun 9 03:38:19 2014 for SuperTux by  doxygen 1.5.1