Add some more sound_manager->preloads into object constructors
[supertux.git] / src / badguy / snail.cpp
1 //  $Id$
2 //
3 //  SuperTux - Badguy "Snail"
4 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.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 "snail.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   const float KICKSPEED_Y = -500; /**< y-velocity gained when kicked */
30 }
31
32 Snail::Snail(const lisp::Lisp& reader)
33   : BadGuy(reader, "images/creatures/snail/snail.sprite"), state(STATE_NORMAL), squishcount(0)
34 {
35   set_direction = false;
36   sound_manager->preload("sounds/iceblock_bump.wav");
37   sound_manager->preload("sounds/stomp.wav");
38   sound_manager->preload("sounds/kick.wav");
39 }
40
41 Snail::Snail(const Vector& pos, Direction d)
42   : BadGuy(pos, "images/creatures/snail/snail.sprite"), state(STATE_NORMAL), squishcount(0)
43 {
44   set_direction = true;
45   initial_direction = d;
46   sound_manager->preload("sounds/iceblock_bump.wav");
47   sound_manager->preload("sounds/stomp.wav");
48   sound_manager->preload("sounds/kick.wav");
49 }
50
51 void
52 Snail::write(lisp::Writer& writer)
53 {
54   writer.start_list("snail");
55
56   writer.write_float("x", start_position.x);
57   writer.write_float("y", start_position.y);
58
59   writer.end_list("snail");
60 }
61
62 void
63 Snail::activate()
64 {
65   if (set_direction) {dir = initial_direction;}
66
67   be_normal();
68 }
69
70 void
71 Snail::be_normal()
72 {
73   state = STATE_NORMAL;
74   sprite->set_action(dir == LEFT ? "left" : "right");
75
76   physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
77 }
78
79 void
80 Snail::be_flat()
81 {
82   state = STATE_FLAT;
83   sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
84   sprite->set_fps(64);
85   
86   physic.set_velocity_x(0);
87   physic.set_velocity_y(0); 
88   
89   flat_timer.start(4);
90 }
91
92 void
93 Snail::be_kicked()
94 {
95   state = STATE_KICKED_DELAY;
96   sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
97   sprite->set_fps(64);
98
99   physic.set_velocity_x(0);
100   physic.set_velocity_y(0); 
101  
102   // start a timer to delay addition of upward movement until we are (hopefully) out from under the player
103   kicked_delay_timer.start(0.05);
104 }
105
106
107 void
108 Snail::active_update(float elapsed_time)
109 {
110   switch (state) {
111
112     case STATE_NORMAL:
113       if (might_fall(601)) {
114         dir = (dir == LEFT ? RIGHT : LEFT);
115         sprite->set_action(dir == LEFT ? "left" : "right");
116         physic.set_velocity_x(-physic.get_velocity_x());
117       }
118       break;
119
120     case STATE_FLAT:
121       if (flat_timer.started()) {
122         sprite->set_fps(64 - 15 * flat_timer.get_timegone());
123       }
124       if (flat_timer.check()) {
125         be_normal();
126       }
127       break;
128
129     case STATE_KICKED_DELAY:
130       if (kicked_delay_timer.check()) {
131         physic.set_velocity_x(dir == LEFT ? -KICKSPEED : KICKSPEED);
132         physic.set_velocity_y(KICKSPEED_Y);
133         state = STATE_KICKED;
134       }
135       break;
136
137     case STATE_KICKED:
138       physic.set_velocity_x(physic.get_velocity_x() * pow(0.99, elapsed_time/0.02));
139       if (fabsf(physic.get_velocity_x()) < WALKSPEED) be_normal();
140       break;
141
142   }
143   BadGuy::active_update(elapsed_time);
144 }
145
146 HitResponse
147 Snail::collision_solid(GameObject& object, const CollisionHit& hit)
148 {
149   if(fabsf(hit.normal.y) > .5) { // floor or roof
150     physic.set_velocity_y(0);
151
152     switch (state) {
153       case STATE_NORMAL:
154       case STATE_FLAT:
155       case STATE_KICKED_DELAY:
156         break;
157       case STATE_KICKED:
158         break;
159     }
160
161     return CONTINUE;
162   }
163   // hit left or right
164   switch(state) {
165     
166     case STATE_NORMAL:
167       dir = dir == LEFT ? RIGHT : LEFT;
168       sprite->set_action(dir == LEFT ? "left" : "right");
169       physic.set_velocity_x(-physic.get_velocity_x());       
170       break;
171
172     case STATE_FLAT:
173     case STATE_KICKED_DELAY:
174       physic.set_velocity_x(0);
175       break;
176
177     case STATE_KICKED: {
178       sound_manager->play("sounds/iceblock_bump.wav", get_pos());
179      
180       // open bonusblocks, crash bricks
181       BonusBlock* bonusblock = dynamic_cast<BonusBlock*> (&object);
182       if(bonusblock) {
183         bonusblock->try_open();
184       }
185       Brick* brick = dynamic_cast<Brick*> (&object);
186       if(brick) {
187         brick->try_break();
188       }
189       
190       dir = (dir == LEFT) ? RIGHT : LEFT;
191       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
192
193       physic.set_velocity_x(-physic.get_velocity_x()*0.75);
194       if (fabsf(physic.get_velocity_x()) < WALKSPEED) be_normal();
195       break;
196
197     }
198   }
199
200   return CONTINUE;
201 }
202
203 HitResponse
204 Snail::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
205 {
206   switch(state) {
207     case STATE_NORMAL:
208       if(fabsf(hit.normal.x) > .5) {
209         dir = (dir == LEFT) ? RIGHT : LEFT;
210         sprite->set_action(dir == LEFT ? "left" : "right");
211         physic.set_velocity_x(-physic.get_velocity_x());               
212       }
213       return CONTINUE;
214     case STATE_FLAT:
215     case STATE_KICKED_DELAY:
216       return FORCE_MOVE;
217     case STATE_KICKED:
218       badguy.kill_fall();
219       return FORCE_MOVE;
220     default:
221       assert(false);
222   }
223
224   return ABORT_MOVE;
225 }
226
227 bool
228 Snail::collision_squished(Player& player)
229 {
230   switch(state) {
231
232     case STATE_KICKED:
233     case STATE_NORMAL:
234       squishcount++;
235       if(squishcount >= MAXSQUISHES) {
236         kill_fall();
237         return true;
238       }
239
240       sound_manager->play("sounds/stomp.wav", get_pos());
241       be_flat();
242       break;
243       
244     case STATE_FLAT:
245       sound_manager->play("sounds/kick.wav", get_pos());
246
247       if(player.get_pos().x < get_pos().x) {
248         dir = RIGHT;
249       } else {
250         dir = LEFT;
251       }
252       be_kicked();
253       break;
254
255     case STATE_KICKED_DELAY:
256       break;
257       
258   }
259
260   player.bounce(*this);
261   return true;
262 }
263
264 IMPLEMENT_FACTORY(Snail, "snail")