* svn:ignored .externalToolBuilders in root directory (Eclipse+CDT)
[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 "yeti.h"
25 #include "object/camera.h"
26 #include "yeti_stalactite.h"
27 #include "bouncing_snowball.h"
28 #include "game_session.h"
29 #include "scripting/script_interpreter.h"
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(80, 120);
45   sprite = sprite_manager->create("yeti");
46   sprite->set_action("right");
47   state = INIT;
48   side = LEFT;
49   sound_manager->preload_sound("yeti_gna");
50   sound_manager->preload_sound("yeti_roar");
51   hit_points = INITIAL_HITPOINTS;
52   reader.get("dead-script", dead_script);
53   countMe = false;
54 }
55
56 Yeti::~Yeti()
57 {
58 }
59
60 void
61 Yeti::draw(DrawingContext& context)
62 {
63   // we blink when we are safe
64   if(safe_timer.started() && size_t(global_time*40)%2)
65     return;
66
67   BadGuy::draw(context);
68 }
69
70 void
71 Yeti::active_update(float elapsed_time)
72 {
73   switch(state) {
74     case INIT:
75       break;
76     case GO_RIGHT:
77       physic.set_velocity_x(RUN_SPEED);
78       if(timer.check())
79         physic.set_velocity_y(JUMP_VEL2);
80       break;
81     case GO_LEFT:
82       physic.set_velocity_x(-RUN_SPEED);
83       if(timer.check())
84         physic.set_velocity_y(JUMP_VEL2);
85       break;
86     case ANGRY_JUMPING:
87       if(timer.check()) {
88         // jump
89         sound_manager->play_sound("yeti_gna");
90         physic.set_velocity_y(JUMP_VEL1);
91       }
92       break;
93     default:
94       break;
95   }
96
97   movement = physic.get_movement(elapsed_time);
98 }
99
100 void
101 Yeti::go_right()
102 {
103   // jump and move right
104   physic.set_velocity_y(JUMP_VEL1);
105   physic.set_velocity_x(RUN_SPEED);
106   state = GO_RIGHT;
107   timer.start(JUMP_TIME);
108 }
109
110 void
111 Yeti::go_left()
112 {
113   physic.set_velocity_y(JUMP_VEL1);
114   physic.set_velocity_x(-RUN_SPEED);
115   state = GO_LEFT;
116   timer.start(JUMP_TIME);
117 }
118
119 void
120 Yeti::angry_jumping()
121 {
122   jumpcount = 0;
123   timer.start(ANGRY_JUMP_WAIT);
124   state = ANGRY_JUMPING;
125   physic.set_velocity_x(0);
126 }
127
128 void
129 Yeti::summon_snowball()
130 {
131   Sector::current()->add_object(new BouncingSnowball(get_pos().x+(side == LEFT ? 64 : -64), get_pos().y, (side == LEFT ? RIGHT : LEFT)));
132 }
133
134 bool
135 Yeti::collision_squished(Player& player)
136 {
137   if(safe_timer.started())
138     return true;
139
140   player.bounce(*this);
141   sound_manager->play_sound("yeti_roar");
142   hit_points--;
143   if(hit_points <= 0) {
144     sprite->set_action("dead");
145     kill_squished(player);
146
147     // start script
148     if(dead_script != "") {
149       try {
150         ScriptInterpreter* interpreter 
151           = new ScriptInterpreter(GameSession::current()->get_working_directory());
152         interpreter->register_sector(Sector::current());
153         std::istringstream in(dead_script);
154         interpreter->load_script(in, "Yeti - dead-script");
155         interpreter->start_script();
156         Sector::current()->add_object(interpreter);
157       } catch(std::exception& e) {
158         std::cerr << "Couldn't execute yeti dead script: " << e.what() << "\n";
159       }
160     }
161   } else {
162     safe_timer.start(SAFE_TIME);
163   }
164   
165   return true;
166 }
167
168 void
169 Yeti::kill_fall()
170 {
171   // shooting bullets or being invincible won't work :)
172 }
173
174 void
175 Yeti::write(lisp::Writer& )
176 {
177 }
178
179 void
180 Yeti::drop_stalactite()
181 {
182   YetiStalactite* nearest = 0;
183   float dist = FLT_MAX;
184
185   Sector* sector = Sector::current();
186   for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
187       i != sector->gameobjects.end(); ++i) {
188     YetiStalactite* stalactite = dynamic_cast<YetiStalactite*> (*i);
189     if(stalactite && stalactite->is_hanging()) {
190       float sdist 
191         = fabsf(stalactite->get_pos().x - sector->player->get_pos().x);
192       if(sdist < dist) {
193         nearest = stalactite;
194         dist = sdist;
195       }
196     }
197   }
198
199   if(nearest)
200     nearest->start_shaking();
201 }
202
203 HitResponse
204 Yeti::collision_solid(GameObject& , const CollisionHit& hit)
205 {
206   if(fabsf(hit.normal.y) > .5) { // hit floor or roof?
207     physic.set_velocity_y(0);
208     if(state == INIT) {
209       go_right();
210     } else if(state == GO_LEFT && !timer.started()) {
211       side = LEFT;
212       summon_snowball();
213       sprite->set_action("right");
214       angry_jumping();
215     } else if(state == GO_RIGHT && !timer.started()) {
216       side = RIGHT;
217       summon_snowball();
218       sprite->set_action("left");
219       angry_jumping();
220     } else if(state == ANGRY_JUMPING) {
221       if(!timer.started()) {
222         // we just landed
223         jumpcount++;
224         // make a stalactite falling down and shake camera a bit
225         Sector::current()->camera->shake(.1, 0, 10);
226         drop_stalactite();
227         
228         // go to other side after 3 jumps
229         if(jumpcount == 3) {
230           if(side == LEFT)
231             go_right();
232           else
233             go_left();
234         } else {
235           // jump again
236           timer.start(ANGRY_JUMP_WAIT);
237         }
238       }
239     }
240   }
241   
242   return CONTINUE;
243 }
244
245 IMPLEMENT_FACTORY(Yeti, "yeti")