Add some more sound_manager->preloads into object constructors
[supertux.git] / src / badguy / mriceblock.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <config.h>
21
22 #include "mriceblock.hpp"
23 #include "object/block.hpp"
24
25 namespace {
26   const float WALKSPEED = 80;
27   const float KICKSPEED = 500;
28   const int MAXSQUISHES = 10;
29 }
30
31 MrIceBlock::MrIceBlock(const lisp::Lisp& reader)
32   : BadGuy(reader, "images/creatures/mr_iceblock/mr_iceblock.sprite"), ice_state(ICESTATE_NORMAL), squishcount(0)
33 {
34   set_direction = false;
35   sound_manager->preload("sounds/iceblock_bump.wav");
36   sound_manager->preload("sounds/stomp.wav");
37   sound_manager->preload("sounds/kick.wav");
38 }
39
40 MrIceBlock::MrIceBlock(const Vector& pos, Direction d)
41   : BadGuy(pos, "images/creatures/mr_iceblock/mr_iceblock.sprite"), ice_state(ICESTATE_NORMAL), squishcount(0)
42 {
43   set_direction = true;
44   initial_direction = d;
45   sound_manager->preload("sounds/iceblock_bump.wav");
46   sound_manager->preload("sounds/stomp.wav");
47   sound_manager->preload("sounds/kick.wav");
48 }
49
50 void
51 MrIceBlock::write(lisp::Writer& writer)
52 {
53   writer.start_list("mriceblock");
54
55   writer.write_float("x", start_position.x);
56   writer.write_float("y", start_position.y);
57
58   writer.end_list("mriceblock");
59 }
60
61 void
62 MrIceBlock::activate()
63 {
64   if (set_direction) {
65     dir = initial_direction;
66   }
67
68   physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
69   sprite->set_action(dir == LEFT ? "left" : "right");
70   set_state(ICESTATE_NORMAL);
71 }
72
73 void
74 MrIceBlock::active_update(float elapsed_time)
75 {
76   if(ice_state == ICESTATE_GRABBED)
77     return;
78
79   if(ice_state == ICESTATE_FLAT && flat_timer.check()) {
80     set_state(ICESTATE_NORMAL);
81   }
82
83   if (ice_state == ICESTATE_NORMAL && might_fall(601))
84   {
85     dir = (dir == LEFT ? RIGHT : LEFT);
86     sprite->set_action(dir == LEFT ? "left" : "right");
87     physic.set_velocity_x(-physic.get_velocity_x());
88   }
89
90   BadGuy::active_update(elapsed_time);
91 }
92
93 HitResponse
94 MrIceBlock::collision_solid(GameObject& object, const CollisionHit& hit)
95 {
96   if(fabsf(hit.normal.y) > .5) { // floor or roof
97     physic.set_velocity_y(0);
98     return CONTINUE;
99   }
100   // hit left or right
101   switch(ice_state) {
102     case ICESTATE_NORMAL:
103       dir = dir == LEFT ? RIGHT : LEFT;
104       sprite->set_action(dir == LEFT ? "left" : "right");
105       physic.set_velocity_x(-physic.get_velocity_x());       
106       break;
107     case ICESTATE_KICKED: {
108       BonusBlock* bonusblock = dynamic_cast<BonusBlock*> (&object);
109       if(bonusblock) {
110         bonusblock->try_open();
111       }
112       Brick* brick = dynamic_cast<Brick*> (&object);
113       if(brick) {
114         brick->try_break();
115       }
116       
117       dir = dir == LEFT ? RIGHT : LEFT;
118       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
119       physic.set_velocity_x(-physic.get_velocity_x());
120       sound_manager->play("sounds/iceblock_bump.wav", get_pos());
121       break;
122     }
123     case ICESTATE_FLAT:
124       physic.set_velocity_x(0);
125       break;
126     case ICESTATE_GRABBED:
127       return FORCE_MOVE;
128   }
129
130   return CONTINUE;
131 }
132
133 HitResponse
134 MrIceBlock::collision(GameObject& object, const CollisionHit& hit)
135 {
136   if(ice_state == ICESTATE_GRABBED)
137     return FORCE_MOVE;
138
139   return BadGuy::collision(object, hit);
140 }
141
142 HitResponse
143 MrIceBlock::collision_player(Player& player, const CollisionHit& hit)
144 {
145   if(ice_state == ICESTATE_GRABBED)
146     return FORCE_MOVE;
147
148   // handle kicks from left or right side
149   if(ice_state == ICESTATE_FLAT && get_state() == STATE_ACTIVE) {
150     // hit from left side
151     if(hit.normal.x > 0.7) {
152       dir = RIGHT;
153       player.kick();
154       set_state(ICESTATE_KICKED);
155       return FORCE_MOVE;
156     } else if(hit.normal.x < -0.7) {
157       dir = LEFT;
158       player.kick();
159       set_state(ICESTATE_KICKED);
160       return FORCE_MOVE;
161     }
162   }
163   
164   return BadGuy::collision_player(player, hit);
165 }
166
167 HitResponse
168 MrIceBlock::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
169 {
170   switch(ice_state) {
171     case ICESTATE_NORMAL:
172       if(fabsf(hit.normal.x) > .8) {
173         dir = dir == LEFT ? RIGHT : LEFT;
174         sprite->set_action(dir == LEFT ? "left" : "right");
175         physic.set_velocity_x(-physic.get_velocity_x());               
176       }
177       return CONTINUE;
178     case ICESTATE_FLAT:
179       return FORCE_MOVE;
180     case ICESTATE_KICKED:
181       badguy.kill_fall();
182       return FORCE_MOVE;
183     default:
184       assert(false);
185   }
186
187   return ABORT_MOVE;
188 }
189
190 bool
191 MrIceBlock::collision_squished(Player& player)
192 {
193   switch(ice_state) {
194     case ICESTATE_KICKED:
195     case ICESTATE_NORMAL:
196       squishcount++;
197       if(squishcount >= MAXSQUISHES) {
198         kill_fall();
199         return true;
200       }
201
202       set_state(ICESTATE_FLAT);
203       break;
204     case ICESTATE_FLAT:
205       if(player.get_pos().x < get_pos().x) {
206         dir = RIGHT;
207       } else {
208         dir = LEFT;
209       }
210       set_state(ICESTATE_KICKED);
211       break;
212     case ICESTATE_GRABBED:
213       assert(false);
214       break;
215   }
216
217   player.bounce(*this);
218   return true;
219 }
220
221 void
222 MrIceBlock::set_state(IceState state)
223 {
224   if(ice_state == state)
225     return;
226   
227   if(state == ICESTATE_FLAT)
228     flags |= FLAG_PORTABLE;
229   else
230     flags &= ~FLAG_PORTABLE;
231
232   switch(state) {
233     case ICESTATE_NORMAL:
234       physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
235       sprite->set_action(dir == LEFT ? "left" : "right");
236       break;
237     case ICESTATE_FLAT:
238       sound_manager->play("sounds/stomp.wav", get_pos());
239       physic.set_velocity_x(0);
240       physic.set_velocity_y(0); 
241       
242       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
243       flat_timer.start(4);
244       break;
245     case ICESTATE_KICKED:
246       sound_manager->play("sounds/kick.wav", get_pos());
247
248       physic.set_velocity_x(dir == LEFT ? -KICKSPEED : KICKSPEED);
249       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
250       // we should slide above 1 block holes now...
251       bbox.set_size(34, 31.8);
252       break;
253     case ICESTATE_GRABBED:
254       flat_timer.stop();
255       break;
256     default:
257       assert(false);
258   }
259   ice_state = state;
260 }
261
262 void
263 MrIceBlock::grab(MovingObject&, const Vector& pos, Direction dir)
264 {
265   movement = pos - get_pos();
266   this->dir = dir;
267   sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
268   set_state(ICESTATE_GRABBED);
269   set_group(COLGROUP_DISABLED);
270 }
271
272 void
273 MrIceBlock::ungrab(MovingObject& , Direction dir)
274 {
275   this->dir = dir;
276   set_state(ICESTATE_KICKED);
277   set_group(COLGROUP_MOVING);
278 }
279
280 IMPLEMENT_FACTORY(MrIceBlock, "mriceblock")