more work on worldmap switching
[supertux.git] / src / badguy / yeti.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2005 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
19 //  02111-1307, USA.
20 #include <config.h>
21
22 #include <float.h>
23 #include <sstream>
24 #include <memory>
25 #include "yeti.hpp"
26 #include "object/camera.hpp"
27 #include "yeti_stalactite.hpp"
28 #include "bouncing_snowball.hpp"
29 #include "game_session.hpp"
30
31 static const float JUMP_VEL1 = 250;
32 static const float JUMP_VEL2 = 700;
33 static const float RUN_SPEED = 350;
34 static const float JUMP_TIME = 1.6;
35 static const float ANGRY_JUMP_WAIT = .5;
36 /// the time we are safe when tux just hit us
37 static const float SAFE_TIME = .5;
38 static const int INITIAL_HITPOINTS = 3;
39
40 Yeti::Yeti(const lisp::Lisp& reader)
41 {
42   reader.get("x", start_position.x);
43   reader.get("y", start_position.y);
44   bbox.set_size(60, 90);
45   sprite = sprite_manager->create("images/creatures/yeti/yeti.sprite");
46   sprite->set_action("right");
47   state = INIT;
48   side = LEFT;
49   hit_points = INITIAL_HITPOINTS;
50   reader.get("dead-script", dead_script);
51   countMe = false;
52 }
53
54 Yeti::~Yeti()
55 {
56 }
57
58 void
59 Yeti::draw(DrawingContext& context)
60 {
61   // we blink when we are safe
62   if(safe_timer.started() && size_t(game_time*40)%2)
63     return;
64
65   BadGuy::draw(context);
66 }
67
68 void
69 Yeti::active_update(float elapsed_time)
70 {
71   switch(state) {
72     case INIT:
73       break;
74     case GO_RIGHT:
75       physic.set_velocity_x(RUN_SPEED);
76       if(timer.check())
77         physic.set_velocity_y(JUMP_VEL2);
78       break;
79     case GO_LEFT:
80       physic.set_velocity_x(-RUN_SPEED);
81       if(timer.check())
82         physic.set_velocity_y(JUMP_VEL2);
83       break;
84     case ANGRY_JUMPING:
85       if(timer.check()) {
86         // jump
87         sound_manager->play("sounds/yeti_gna.wav");
88         physic.set_velocity_y(JUMP_VEL1);
89         if (side == LEFT)  // on the left, facing Tux who is on the right
90           sprite->set_action("jump-right");
91         else
92           sprite->set_action("jump-left");
93       }
94       break;
95     default:
96       break;
97   }
98
99   movement = physic.get_movement(elapsed_time);
100 }
101
102 void
103 Yeti::go_right()
104 {
105   // jump and move right
106   sprite->set_action("right");
107   physic.set_velocity_y(JUMP_VEL1);
108   physic.set_velocity_x(RUN_SPEED);
109   state = GO_RIGHT;
110   timer.start(JUMP_TIME);
111 }
112
113 void
114 Yeti::go_left()
115 {
116   sprite->set_action("left");
117   physic.set_velocity_y(JUMP_VEL1);
118   physic.set_velocity_x(-RUN_SPEED);
119   state = GO_LEFT;
120   timer.start(JUMP_TIME);
121 }
122
123 void
124 Yeti::angry_jumping()
125 {
126   jumpcount = 0;
127   timer.start(ANGRY_JUMP_WAIT);
128   state = ANGRY_JUMPING;
129   physic.set_velocity_x(0);
130 }
131
132 void
133 Yeti::summon_snowball()
134 {
135   Sector::current()->add_object(new BouncingSnowball(get_pos().x+(side == LEFT ? 64 : -64), get_pos().y, (side == LEFT ? RIGHT : LEFT)));
136 }
137
138 bool
139 Yeti::collision_squished(Player& player)
140 {
141   if(safe_timer.started())
142     return true;
143
144   player.bounce(*this);
145   sound_manager->play("sounds/yeti_roar.wav");
146   hit_points--;
147   if(hit_points <= 0) {
148     sprite->set_action("dead");
149     kill_squished(player);
150
151     // start script
152     if(dead_script != "") {
153       std::istringstream stream(dead_script);
154       Sector::current()->run_script(stream, "Yeti - dead-script");
155     }
156   } else {
157     safe_timer.start(SAFE_TIME);
158   }
159   
160   return true;
161 }
162
163 void
164 Yeti::kill_fall()
165 {
166   // shooting bullets or being invincible won't work :)
167 }
168
169 void
170 Yeti::write(lisp::Writer& writer)
171 {
172   writer.start_list("yeti");
173
174   writer.write_float("x", start_position.x);
175   writer.write_float("y", start_position.y);
176
177   if(dead_script != "") {
178     writer.write_string("dead-script", dead_script);
179   }
180
181   writer.end_list("yeti");
182 }
183
184 void
185 Yeti::drop_stalactite()
186 {
187   YetiStalactite* nearest = 0;
188   float dist = FLT_MAX;
189
190   Player* player = this->get_nearest_player();
191   if (!player) return;
192
193   Sector* sector = Sector::current();
194   for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
195       i != sector->gameobjects.end(); ++i) {
196     YetiStalactite* stalactite = dynamic_cast<YetiStalactite*> (*i);
197     if(stalactite && stalactite->is_hanging()) {
198       float sdist 
199         = fabsf(stalactite->get_pos().x - player->get_pos().x);
200       if(sdist < dist) {
201         nearest = stalactite;
202         dist = sdist;
203       }
204     }
205   }
206
207   if(nearest)
208     nearest->start_shaking();
209 }
210
211 HitResponse
212 Yeti::collision_solid(GameObject& , const CollisionHit& hit)
213 {
214   if(fabsf(hit.normal.y) > .5) { // hit floor or roof?
215     physic.set_velocity_y(0);
216     if(state == INIT) {
217       go_right();
218     } else if(state == GO_LEFT && !timer.started()) {
219       side = LEFT;
220       summon_snowball();
221       sprite->set_action("stand-right");
222       angry_jumping();
223     } else if(state == GO_RIGHT && !timer.started()) {
224       side = RIGHT;
225       summon_snowball();
226       sprite->set_action("stand-left");
227       angry_jumping();
228     } else if(state == ANGRY_JUMPING) {
229       if(!timer.started()) {
230         // we just landed
231         if (side == LEFT)  // standing on the left, facing Tux who is on the right
232               sprite->set_action("stand-right");
233             else
234               sprite->set_action("stand-left");
235         jumpcount++;
236         // make a stalactite falling down and shake camera a bit
237         Sector::current()->camera->shake(.1, 0, 10);
238         drop_stalactite();
239         
240         // go to other side after 3 jumps
241         if(jumpcount == 3) {
242           if(side == LEFT)
243             go_right();
244           else
245             go_left();
246         } else {
247           // jump again
248           timer.start(ANGRY_JUMP_WAIT);
249         }
250       }
251     }
252   }
253   
254   return CONTINUE;
255 }
256
257 IMPLEMENT_FACTORY(Yeti, "yeti")