2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "badguy/mriceblock.hpp"
19 #include "audio/sound_manager.hpp"
20 #include "object/player.hpp"
21 #include "sprite/sprite.hpp"
22 #include "sprite/sprite_manager.hpp"
23 #include "supertux/object_factory.hpp"
28 const float KICKSPEED = 500;
29 const int MAXSQUISHES = 10;
30 const float NOKICK_TIME = 0.1f;
33 MrIceBlock::MrIceBlock(const Reader& reader) :
34 WalkingBadguy(reader, "images/creatures/mr_iceblock/mr_iceblock.sprite", "left", "right"),
35 ice_state(ICESTATE_NORMAL),
41 max_drop_height = 600;
42 SoundManager::current()->preload("sounds/iceblock_bump.wav");
43 SoundManager::current()->preload("sounds/stomp.wav");
44 SoundManager::current()->preload("sounds/kick.wav");
47 MrIceBlock::MrIceBlock(const Vector& pos, Direction d) :
48 WalkingBadguy(pos, d, "images/creatures/mr_iceblock/mr_iceblock.sprite", "left", "right"),
49 ice_state(ICESTATE_NORMAL),
55 max_drop_height = 600;
56 SoundManager::current()->preload("sounds/iceblock_bump.wav");
57 SoundManager::current()->preload("sounds/stomp.wav");
58 SoundManager::current()->preload("sounds/kick.wav");
62 MrIceBlock::initialize()
64 WalkingBadguy::initialize();
65 set_state(ICESTATE_NORMAL);
69 MrIceBlock::active_update(float elapsed_time)
71 if(ice_state == ICESTATE_GRABBED)
74 if(ice_state == ICESTATE_FLAT && flat_timer.check()) {
75 set_state(ICESTATE_NORMAL);
78 if (ice_state == ICESTATE_NORMAL)
80 WalkingBadguy::active_update(elapsed_time);
84 BadGuy::active_update(elapsed_time);
88 MrIceBlock::can_break(){
89 return ice_state == ICESTATE_KICKED;
93 MrIceBlock::collision_solid(const CollisionHit& hit)
95 update_on_ground_flag(hit);
97 if(hit.top || hit.bottom) { // floor or roof
98 physic.set_velocity_y(0);
103 case ICESTATE_NORMAL:
104 WalkingBadguy::collision_solid(hit);
106 case ICESTATE_KICKED: {
107 if((hit.right && dir == RIGHT) || (hit.left && dir == LEFT)) {
108 dir = (dir == LEFT) ? RIGHT : LEFT;
109 SoundManager::current()->play("sounds/iceblock_bump.wav", get_pos());
110 physic.set_velocity_x(-physic.get_velocity_x()*.975);
112 this->set_action(dir == LEFT ? "flat-left" : "flat-right", /* loops = */ -1);
113 if(fabsf(physic.get_velocity_x()) < walk_speed*1.5)
114 set_state(ICESTATE_NORMAL);
118 physic.set_velocity_x(0);
120 case ICESTATE_GRABBED:
126 MrIceBlock::collision(GameObject& object, const CollisionHit& hit)
128 if(ice_state == ICESTATE_GRABBED)
131 return BadGuy::collision(object, hit);
135 MrIceBlock::collision_player(Player& player, const CollisionHit& hit)
137 // handle kicks from left or right side
138 if(ice_state == ICESTATE_FLAT && get_state() == STATE_ACTIVE) {
142 set_state(ICESTATE_KICKED);
144 } else if(hit.right) {
147 set_state(ICESTATE_KICKED);
152 return BadGuy::collision_player(player, hit);
156 MrIceBlock::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
159 case ICESTATE_NORMAL:
160 return WalkingBadguy::collision_badguy(badguy, hit);
163 case ICESTATE_KICKED:
174 MrIceBlock::collision_squished(GameObject& object)
176 Player* player = dynamic_cast<Player*>(&object);
177 if(player && (player->does_buttjump || player->is_invincible())) {
178 player->bounce(*this);
184 case ICESTATE_KICKED:
186 BadGuy* badguy = dynamic_cast<BadGuy*>(&object);
194 case ICESTATE_NORMAL:
197 if (squishcount >= MAXSQUISHES) {
203 set_state(ICESTATE_FLAT);
204 nokick_timer.start(NOKICK_TIME);
208 MovingObject* movingobject = dynamic_cast<MovingObject*>(&object);
209 if (movingobject && (movingobject->get_pos().x < get_pos().x)) {
215 if (nokick_timer.check()) set_state(ICESTATE_KICKED);
217 case ICESTATE_GRABBED:
222 if (player) player->bounce(*this);
227 MrIceBlock::set_state(IceState state_, bool up)
229 if(ice_state == state_)
233 case ICESTATE_NORMAL:
234 this->set_action(dir == LEFT ? "left" : "right", /* loops = */ -1);
235 WalkingBadguy::initialize();
239 physic.set_velocity_y(-KICKSPEED);
241 SoundManager::current()->play("sounds/stomp.wav", get_pos());
242 physic.set_velocity_x(0);
243 physic.set_velocity_y(0);
245 this->set_action(dir == LEFT ? "flat-left" : "flat-right", /* loops = */ -1);
248 case ICESTATE_KICKED:
249 SoundManager::current()->play("sounds/kick.wav", get_pos());
251 physic.set_velocity_x(dir == LEFT ? -KICKSPEED : KICKSPEED);
252 this->set_action(dir == LEFT ? "flat-left" : "flat-right", /* loops = */ -1);
253 // we should slide above 1 block holes now...
254 bbox.set_size(34, 31.8f);
256 case ICESTATE_GRABBED:
266 MrIceBlock::grab(MovingObject&, const Vector& pos, Direction dir_)
268 movement = pos - get_pos();
270 this->set_action(dir_ == LEFT ? "flat-left" : "flat-right", /* loops = */ -1);
271 set_state(ICESTATE_GRABBED);
272 set_colgroup_active(COLGROUP_DISABLED);
276 MrIceBlock::ungrab(MovingObject& , Direction dir_)
279 set_state(ICESTATE_FLAT, true);
282 set_state(ICESTATE_KICKED);
284 set_colgroup_active(COLGROUP_MOVING);
288 MrIceBlock::is_portable() const
290 return ice_state == ICESTATE_FLAT;
293 SmartBlock::SmartBlock(const Reader& reader) :
296 max_drop_height = 16;
297 sprite = SpriteManager::current()->create("images/creatures/mr_iceblock/smart_block/smart_block.sprite");