1 // IceCrusher - A block to stand on, which can drop down to crush the player
2 // Copyright (C) 2008 Christoph Sommer <christoph.sommer@2008.expires.deltadevelopment.de>
3 // Copyright (C) 2010 Florian Forster <supertux at octo.it>
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "object/icecrusher.hpp"
20 #include "audio/sound_manager.hpp"
21 #include "badguy/badguy.hpp"
22 //#include "math/random_generator.hpp"
23 #include "object/camera.hpp"
24 #include "object/particles.hpp"
25 #include "object/player.hpp"
26 #include "sprite/sprite.hpp"
27 #include "supertux/object_factory.hpp"
28 #include "supertux/sector.hpp"
31 /* Maximum movement speed in pixels per LOGICAL_FPS */
32 const float MAX_DROP_SPEED = 10.0;
33 const float RECOVER_SPEED_NORMAL = -3.125;
34 const float RECOVER_SPEED_LARGE = -2.0;
35 const float DROP_ACTIVATION_DISTANCE = 4.0;
36 const float PAUSE_TIME_NORMAL = 0.5;
37 const float PAUSE_TIME_LARGE = 1.0;
40 IceCrusher::IceCrusher(const Reader& reader) :
41 MovingSprite(reader, "images/creatures/icecrusher/icecrusher.sprite", LAYER_OBJECTS, COLGROUP_STATIC),
48 // TODO: icecrusher hitting deserves its own sounds-
49 // one for hitting the ground, one for hitting Tux
50 sound_manager->preload("sounds/brick.wav");
52 start_position = get_bbox().p1;
53 set_state(state, true);
55 float sprite_width = sprite->get_width ();
56 if (sprite_width >= 128.0)
61 IceCrusher::IceCrusher(const IceCrusher& other)
62 : MovingSprite(other),
63 state(other.state), speed(other.speed)
65 start_position = get_bbox().p1;
66 set_state(state, true);
70 IceCrusher::set_state(IceCrusherState state, bool force)
72 if ((this->state == state) && (!force)) return;
75 set_group(COLGROUP_STATIC);
76 physic.enable_gravity (false);
77 sprite->set_action("idle");
80 set_group(COLGROUP_MOVING_STATIC);
82 physic.enable_gravity (true);
83 sprite->set_action("crushing");
86 set_group(COLGROUP_MOVING_STATIC);
87 physic.enable_gravity (false);
88 sprite->set_action("recovering");
91 log_debug << "IceCrusher in invalid state" << std::endl;
98 IceCrusher::collision(GameObject& other, const CollisionHit& hit)
100 Player* player = dynamic_cast<Player*>(&other);
102 /* If the other object is the player, and the collision is at the bottom of
103 * the ice crusher, hurt the player. */
104 if (player && hit.bottom) {
105 sound_manager->play("sounds/brick.wav");
106 if(player->is_invincible()) {
107 if (state == CRUSHING)
108 set_state(RECOVERING);
112 if (state == CRUSHING)
113 set_state(RECOVERING);
116 BadGuy* badguy = dynamic_cast<BadGuy*>(&other);
124 IceCrusher::collision_solid(const CollisionHit& hit)
131 if (ic_size == LARGE) {
132 cooldown_timer = PAUSE_TIME_LARGE;
133 Sector::current()->camera->shake (/* frequency = */ .125f, /* x = */ 0.0, /* y = */ 16.0);
134 sound_manager->play("sounds/brick.wav");
135 // throw some particles, bigger and more for large icecrusher
136 for(int j = 0; j < 9; j++)
138 Sector::current()->add_object(
139 new Particles(Vector(get_bbox().p2.x - j*8 - 4, get_bbox().p2.y),
140 0, 90-5*j, Vector(140, -380), Vector(0, 300),
141 1, Color(.6f, .6f, .6f), 5, 1.8f, LAYER_OBJECTS+1));
142 Sector::current()->add_object(
143 new Particles(Vector(get_bbox().p1.x + j*8 + 4, get_bbox().p2.y),
144 270+5*j, 360, Vector(140, -380), Vector(0, 300),
145 1, Color(.6f, .6f, .6f), 5, 1.8f, LAYER_OBJECTS+1));
149 cooldown_timer = PAUSE_TIME_NORMAL;
150 Sector::current()->camera->shake (/* frequency = */ .1f, /* x = */ 0.0, /* y = */ 8.0);
151 sound_manager->play("sounds/brick.wav");
152 // throw some particles
153 for(int j = 0; j < 5; j++)
155 Sector::current()->add_object(
156 new Particles(Vector(get_bbox().p2.x - j*8 - 4, get_bbox().p2.y),
157 0, 90+10*j, Vector(140, -260), Vector(0, 300),
158 1, Color(.6f, .6f, .6f), 4, 1.6f, LAYER_OBJECTS+1));
159 Sector::current()->add_object(
160 new Particles(Vector(get_bbox().p1.x + j*8 + 4, get_bbox().p2.y),
161 270+10*j, 360, Vector(140, -260), Vector(0, 300),
162 1, Color(.6f, .6f, .6f), 4, 1.6f, LAYER_OBJECTS+1));
165 set_state(RECOVERING);
171 log_debug << "IceCrusher in invalid state" << std::endl;
177 IceCrusher::update(float elapsed_time)
179 if (cooldown_timer >= elapsed_time)
181 cooldown_timer -= elapsed_time;
184 else if (cooldown_timer != 0.0)
186 elapsed_time -= cooldown_timer;
187 cooldown_timer = 0.0;
192 movement = Vector (0, 0);
197 movement = physic.get_movement (elapsed_time);
198 if (movement.y > MAX_DROP_SPEED)
199 movement.y = MAX_DROP_SPEED;
202 if (get_bbox().p1.y <= start_position.y+1) {
203 set_pos(start_position);
204 movement = Vector (0, 0);
205 if (ic_size == LARGE)
206 cooldown_timer = PAUSE_TIME_LARGE;
208 cooldown_timer = PAUSE_TIME_NORMAL;
212 if (ic_size == LARGE)
213 movement = Vector (0, RECOVER_SPEED_LARGE);
215 movement = Vector (0, RECOVER_SPEED_NORMAL);
219 log_debug << "IceCrusher in invalid state" << std::endl;
225 IceCrusher::found_victim()
227 Player* player = Sector::current()->get_nearest_player (this->get_bbox ());
228 if (!player) return false;
230 const Rectf& player_bbox = player->get_bbox();
231 const Rectf& crusher_bbox = get_bbox();
232 if ((player_bbox.p1.y >= crusher_bbox.p2.y) /* player is below crusher */
233 && (player_bbox.p2.x > (crusher_bbox.p1.x - DROP_ACTIVATION_DISTANCE))
234 && (player_bbox.p1.x < (crusher_bbox.p2.x + DROP_ACTIVATION_DISTANCE)))