00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00055
00056
00057
00058
00059
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
00096
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 ( .125f, 0.0, 16.0);
00126 }
00127 else {
00128 cooldown_timer = PAUSE_TIME_NORMAL;
00129 Sector::current()->camera->shake ( .1f, 0.0, 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)
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