icecrusher.cpp: Remove debug message.
[supertux.git] / src / object / icecrusher.cpp
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>
4 //
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.
9 //
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.
14 //
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/>.
17
18 #include "object/icecrusher.hpp"
19
20 #include "badguy/badguy.hpp"
21 #include "sprite/sprite.hpp"
22 #include "object/player.hpp"
23 #include "object/camera.hpp"
24 #include "supertux/object_factory.hpp"
25 #include "supertux/sector.hpp"
26
27 namespace {
28 /* Maximum movement speed in pixels per LOGICAL_FPS */
29 const float MAX_DROP_SPEED = 10.0;
30 const float RECOVER_SPEED_NORMAL = -3.125;
31 const float RECOVER_SPEED_LARGE  = -2.0;
32 const float DROP_ACTIVATION_DISTANCE = 4.0;
33 const float PAUSE_TIME_NORMAL = 0.5;
34 const float PAUSE_TIME_LARGE  = 1.0;
35 }
36
37 IceCrusher::IceCrusher(const Reader& reader) :
38   MovingSprite(reader, "images/creatures/icecrusher/icecrusher.sprite", LAYER_OBJECTS, COLGROUP_STATIC), 
39   state(IDLE), 
40   start_position(),
41   physic(),
42   cooldown_timer(0.0),
43   ic_size(NORMAL)
44 {
45   start_position = get_bbox().p1;
46   set_state(state, true);
47   
48   float sprite_width = sprite->get_width ();
49   if (sprite_width >= 128.0)
50     ic_size = LARGE;
51 }
52
53 /*
54   IceCrusher::IceCrusher(const IceCrusher& other)
55   : MovingSprite(other), 
56   state(other.state), speed(other.speed) 
57   {
58   start_position = get_bbox().p1;
59   set_state(state, true);
60   }
61 */
62 void 
63 IceCrusher::set_state(IceCrusherState state, bool force) 
64 {
65   if ((this->state == state) && (!force)) return;
66   switch(state) {
67     case IDLE:
68       set_group(COLGROUP_STATIC);
69       physic.enable_gravity (false);
70       sprite->set_action("idle");
71       break;
72     case CRUSHING:
73       set_group(COLGROUP_MOVING_STATIC);
74       physic.reset ();
75       physic.enable_gravity (true);
76       sprite->set_action("crushing");
77       break;
78     case RECOVERING:
79       set_group(COLGROUP_MOVING_STATIC);
80       physic.enable_gravity (false);
81       sprite->set_action("recovering");
82       break;
83     default:
84       log_debug << "IceCrusher in invalid state" << std::endl;
85       break;
86   }
87   this->state = state;
88 }
89
90 HitResponse
91 IceCrusher::collision(GameObject& other, const CollisionHit& hit)
92 {
93   Player* player = dynamic_cast<Player*>(&other);
94
95   /* If the other object is the player, and the collision is at the bottom of
96    * the ice crusher, hurt the player. */
97   if (player && hit.bottom) {
98     if(player->is_invincible()) {
99       if (state == CRUSHING)
100         set_state(RECOVERING);
101       return ABORT_MOVE;
102     }
103     player->kill(false);
104     if (state == CRUSHING)
105       set_state(RECOVERING);
106     return FORCE_MOVE;
107   }
108   BadGuy* badguy = dynamic_cast<BadGuy*>(&other);
109   if (badguy) {
110     badguy->kill_fall();
111   }
112   return FORCE_MOVE;
113 }
114     
115 void 
116 IceCrusher::collision_solid(const CollisionHit& hit)
117 {
118   switch(state) {
119     case IDLE:
120       break;
121     case CRUSHING:
122       if (hit.bottom) {
123         if (ic_size == LARGE) {
124           cooldown_timer = PAUSE_TIME_LARGE;
125           Sector::current()->camera->shake (/* frequency = */ .125f, /* x = */ 0.0, /* y = */ 16.0);
126         }
127         else {
128           cooldown_timer = PAUSE_TIME_NORMAL;
129           Sector::current()->camera->shake (/* frequency = */ .1f, /* x = */ 0.0, /* y = */ 8.0);
130         }
131         set_state(RECOVERING);
132       }
133       break;
134     case RECOVERING:
135       break;
136     default:
137       log_debug << "IceCrusher in invalid state" << std::endl;
138       break;
139   }
140 }
141
142 void
143 IceCrusher::update(float elapsed_time)
144 {
145   if (cooldown_timer >= elapsed_time)
146   {
147     cooldown_timer -= elapsed_time;
148     return;
149   }
150   else if (cooldown_timer != 0.0)
151   {
152     elapsed_time -= cooldown_timer;
153     cooldown_timer = 0.0;
154   }
155
156   switch(state) {
157     case IDLE:
158       movement = Vector (0, 0);
159       if (found_victim())
160         set_state(CRUSHING);
161       break;
162     case CRUSHING:
163       movement = physic.get_movement (elapsed_time);
164       if (movement.y > MAX_DROP_SPEED)
165         movement.y = MAX_DROP_SPEED;
166       break;
167     case RECOVERING:
168       if (get_bbox().p1.y <= start_position.y+1) {
169         set_pos(start_position);
170         movement = Vector (0, 0);
171         if (ic_size == LARGE)
172           cooldown_timer = PAUSE_TIME_LARGE;
173         else
174           cooldown_timer = PAUSE_TIME_NORMAL;
175         set_state(IDLE);
176       }
177       else {
178         if (ic_size == LARGE)
179           movement = Vector (0, RECOVER_SPEED_LARGE);
180         else
181           movement = Vector (0, RECOVER_SPEED_NORMAL);
182       }
183       break;
184     default:
185       log_debug << "IceCrusher in invalid state" << std::endl;
186       break;
187   }
188 }
189
190 bool
191 IceCrusher::found_victim()
192 {
193   Player* player = Sector::current()->get_nearest_player (this->get_bbox ());
194   if (!player) return false;
195
196   const Rectf& player_bbox = player->get_bbox();
197   const Rectf& crusher_bbox = get_bbox();
198   if ((player_bbox.p1.y >= crusher_bbox.p2.y) /* player is below crusher */
199       && (player_bbox.p2.x > (crusher_bbox.p1.x - DROP_ACTIVATION_DISTANCE))
200       && (player_bbox.p1.x < (crusher_bbox.p2.x + DROP_ACTIVATION_DISTANCE)))
201     return true;
202   else
203     return false;
204 }
205
206 /* EOF */