Hardcoded stay-on-platform behaviour as follows: Mr. Bomb, Mr. Tree and the Totem...
[supertux.git] / src / badguy / snowsnail.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 "snowsnail.hpp"
23 #include "object/block.hpp"
24
25 static const float WALKSPEED = 80;
26 static const float KICKSPEED = 500;
27 static const int MAXSQUISHES = 10;
28
29 SnowSnail::SnowSnail(const lisp::Lisp& reader)
30   : ice_state(ICESTATE_NORMAL), squishcount(0)
31 {
32   reader.get("x", start_position.x);
33   reader.get("y", start_position.y);
34   bbox.set_size(31.8, 31.8);
35   sprite = sprite_manager->create("images/creatures/snowsnail/snowsnail.sprite");
36   set_direction = false;
37 }
38
39 SnowSnail::SnowSnail(float pos_x, float pos_y, Direction d)
40   : ice_state(ICESTATE_NORMAL), squishcount(0)
41 {
42   start_position.x = pos_x;
43   start_position.y = pos_y;
44   bbox.set_size(31.8, 31.8);
45   sprite = sprite_manager->create("images/creatures/snowsnail/snowsnail.sprite");
46   set_direction = true;
47   initial_direction = d;
48 }
49
50 void
51 SnowSnail::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("snowsnail");
59 }
60
61 void
62 SnowSnail::activate()
63 {
64   if (set_direction) {dir = initial_direction;}
65   physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
66   sprite->set_action(dir == LEFT ? "left" : "right");
67 }
68
69 void
70 SnowSnail::active_update(float elapsed_time)
71 {
72   if((ice_state != ICESTATE_KICKED) && flat_timer.started()) {
73     sprite->set_fps(64 - 15 * flat_timer.get_timegone());
74   }
75   if(ice_state == ICESTATE_FLAT && flat_timer.check()) {
76     ice_state = ICESTATE_NORMAL;
77     physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
78     sprite->set_action(dir == LEFT ? "left" : "right");
79   }
80   BadGuy::active_update(elapsed_time);
81 }
82
83 HitResponse
84 SnowSnail::collision_solid(GameObject& object, const CollisionHit& hit)
85 {
86   if(fabsf(hit.normal.y) > .5) { // floor or roof
87     physic.set_velocity_y(0);
88     return CONTINUE;
89   }
90   // hit left or right
91   switch(ice_state) {
92     case ICESTATE_NORMAL:
93       dir = dir == LEFT ? RIGHT : LEFT;
94       sprite->set_action(dir == LEFT ? "left" : "right");
95       physic.set_velocity_x(-physic.get_velocity_x());       
96       break;
97     case ICESTATE_KICKED: {
98       BonusBlock* bonusblock = dynamic_cast<BonusBlock*> (&object);
99       if(bonusblock) {
100         bonusblock->try_open();
101       }
102       Brick* brick = dynamic_cast<Brick*> (&object);
103       if(brick) {
104         brick->try_break();
105       }
106       
107       dir = dir == LEFT ? RIGHT : LEFT;
108       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
109       sprite->set_fps(64);
110       physic.set_velocity_x(-physic.get_velocity_x());
111       sound_manager->play("sounds/iceblock_bump.wav", get_pos());
112       break;
113     }
114     case ICESTATE_FLAT:
115       physic.set_velocity_x(0);
116       break;
117   }
118
119   return CONTINUE;
120 }
121
122 HitResponse
123 SnowSnail::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
124 {
125   switch(ice_state) {
126     case ICESTATE_NORMAL:
127       if(fabsf(hit.normal.x) > .8) {
128         dir = dir == LEFT ? RIGHT : LEFT;
129         sprite->set_action(dir == LEFT ? "left" : "right");
130         physic.set_velocity_x(-physic.get_velocity_x());               
131       }
132       return CONTINUE;
133     case ICESTATE_FLAT:
134       return FORCE_MOVE;
135     case ICESTATE_KICKED:
136       badguy.kill_fall();
137       return FORCE_MOVE;
138     default:
139       assert(false);
140   }
141
142   return ABORT_MOVE;
143 }
144
145 bool
146 SnowSnail::collision_squished(Player& player)
147 {
148   switch(ice_state) {
149     case ICESTATE_KICKED:
150     case ICESTATE_NORMAL:
151       squishcount++;
152       if(squishcount >= MAXSQUISHES) {
153         kill_fall();
154         return true;
155       }
156
157       // flatten
158       sound_manager->play("sounds/stomp.wav", get_pos());
159       physic.set_velocity_x(0);
160       physic.set_velocity_y(0); 
161       
162       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
163       sprite->set_fps(64);
164       flat_timer.start(4);
165       ice_state = ICESTATE_FLAT;
166       break;
167     case ICESTATE_FLAT:
168       // kick
169       sound_manager->play("sounds/kick.wav", get_pos());
170
171       if(player.get_pos().x < get_pos().x) {
172         dir = RIGHT;
173       } else {
174         dir = LEFT;
175       }
176       physic.set_velocity_x(dir == LEFT ? -KICKSPEED : KICKSPEED);
177       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
178       sprite->set_fps(64);
179       ice_state = ICESTATE_KICKED;
180       break;
181   }
182
183   player.bounce(*this);
184   return true;
185 }
186
187 IMPLEMENT_FACTORY(SnowSnail, "snowsnail")