More debug markers before debug statements in willowisp.cpp
[supertux.git] / src / badguy / willowisp.cpp
1 //  SuperTux - "Will-O-Wisp" Badguy
2 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "badguy/willowisp.hpp"
18
19 #include "audio/sound_manager.hpp"
20 #include "audio/sound_source.hpp"
21 #include "object/lantern.hpp"
22 #include "object/path_walker.hpp"
23 #include "object/player.hpp"
24 #include "scripting/squirrel_util.hpp"
25 #include "sprite/sprite.hpp"
26 #include "sprite/sprite_manager.hpp"
27 #include "supertux/game_session.hpp"
28 #include "supertux/object_factory.hpp"
29 #include "supertux/sector.hpp"
30 #include "util/reader.hpp"
31
32 static const float FLYSPEED = 64; /**< speed in px per second */
33 static const float TRACK_RANGE = 384; /**< at what distance to start tracking the player */
34 static const float VANISH_RANGE = 512; /**< at what distance to stop tracking and vanish */
35 static const std::string SOUNDFILE = "sounds/willowisp.wav";
36
37 WillOWisp::WillOWisp(const Reader& reader) :
38   BadGuy(reader, "images/creatures/willowisp/willowisp.sprite", LAYER_FLOATINGOBJECTS), 
39   mystate(STATE_IDLE), 
40   target_sector("main"), 
41   target_spawnpoint("main"),
42   hit_script(),
43   sound_source(),
44   path(),
45   walker(),
46   flyspeed(),
47   track_range(),
48   vanish_range(),
49   lightsprite(sprite_manager->create("images/objects/lightmap_light/lightmap_light-small.sprite"))
50 {
51   bool running = false;
52   flyspeed     = FLYSPEED;
53   track_range  = TRACK_RANGE;
54   vanish_range = VANISH_RANGE;
55
56   reader.get("sector", target_sector);
57   reader.get("spawnpoint", target_spawnpoint);
58   reader.get("name", name);
59   reader.get("flyspeed", flyspeed);
60   reader.get("track-range", track_range);
61   reader.get("vanish-range", vanish_range);
62   reader.get("hit-script", hit_script);
63   reader.get("running", running);
64
65   const lisp::Lisp* pathLisp = reader.get_lisp("path");
66   if(pathLisp != NULL) {
67     path.reset(new Path());
68     path->read(*pathLisp);
69     walker.reset(new PathWalker(path.get(), running));
70     if(running)
71       mystate = STATE_PATHMOVING_TRACK;
72   }
73
74   countMe = false;
75   sound_manager->preload(SOUNDFILE);
76   sound_manager->preload("sounds/warp.wav");
77
78   lightsprite->set_blend(Blend(GL_SRC_ALPHA, GL_ONE));
79   lightsprite->set_color(Color(0.0f, 0.2f, 0.0f));
80
81   sprite->set_action("idle");
82 }
83
84 void
85 WillOWisp::draw(DrawingContext& context)
86 {
87   sprite->draw(context, get_pos(), layer);
88
89   context.push_target();
90   context.set_target(DrawingContext::LIGHTMAP);
91
92   sprite->draw(context, get_pos(), layer);
93   lightsprite->draw(context, get_bbox().get_middle(), 0);
94
95   context.pop_target();
96 }
97
98 void
99 WillOWisp::active_update(float elapsed_time)
100 {
101   Player* player = get_nearest_player();
102   if (!player) return;
103   Vector p1 = this->get_pos() + (this->get_bbox().p2 - this->get_bbox().p1) / 2;
104   Vector p2 = player->get_pos() + (player->get_bbox().p2 - player->get_bbox().p1) / 2;
105   Vector dist = (p2 - p1);
106
107   switch(mystate) {
108     case STATE_STOPPED:
109       break;
110
111     case STATE_IDLE:
112       if (dist.norm() <= track_range) {
113         mystate = STATE_TRACKING;
114       }
115       break;
116
117     case STATE_TRACKING:
118       if (dist.norm() > vanish_range) {
119         vanish();
120       } else if (dist.norm() >= 1) {
121         Vector dir = dist.unit();
122         movement = dir * elapsed_time * flyspeed;
123       } else {
124         /* We somehow landed right on top of the player without colliding.
125          * Sit tight and avoid a division by zero. */
126       }
127       sound_source->set_position(get_pos());
128       break;
129
130     case STATE_WARPING:
131       if(sprite->animation_done()) {
132         remove_me();
133       }
134
135     case STATE_VANISHING: {
136       Vector dir = dist.unit();
137       movement = dir * elapsed_time * flyspeed;
138       if(sprite->animation_done()) {
139         remove_me();
140       }
141       break;
142     }
143
144     case STATE_PATHMOVING:
145     case STATE_PATHMOVING_TRACK:
146       if(walker.get() == NULL)
147         return;
148       movement = walker->advance(elapsed_time) - get_pos();
149       if(mystate == STATE_PATHMOVING_TRACK && dist.norm() <= track_range) {
150         mystate = STATE_TRACKING;
151       }
152       break;
153
154     default:
155       assert(false);
156   }
157 }
158
159 void
160 WillOWisp::activate()
161 {
162   sound_source.reset(sound_manager->create_sound_source(SOUNDFILE));
163   sound_source->set_position(get_pos());
164   sound_source->set_looping(true);
165   sound_source->set_gain(2.0);
166   sound_source->set_reference_distance(32);
167   sound_source->play();
168 }
169
170 void
171 WillOWisp::deactivate()
172 {
173   sound_source.reset(NULL);
174
175   switch (mystate) {
176     case STATE_STOPPED:
177     case STATE_IDLE:
178     case STATE_PATHMOVING:
179     case STATE_PATHMOVING_TRACK:
180       break;
181     case STATE_TRACKING:
182       mystate = STATE_IDLE;
183       break;
184     case STATE_WARPING:
185     case STATE_VANISHING:
186       remove_me();
187       break;
188   }
189 }
190
191 void
192 WillOWisp::vanish()
193 {
194   mystate = STATE_VANISHING;
195   sprite->set_action("vanishing", 1);
196   set_colgroup_active(COLGROUP_DISABLED);
197 }
198
199 bool
200 WillOWisp::collides(GameObject& other, const CollisionHit& ) {
201   Lantern* lantern = dynamic_cast<Lantern*>(&other);
202
203   if (lantern && lantern->is_open())
204     return true;
205
206   if (dynamic_cast<Player*>(&other))
207     return true;
208
209   return false;
210 }
211
212 HitResponse
213 WillOWisp::collision_player(Player& player, const CollisionHit& ) {
214   if(player.is_invincible())
215     return ABORT_MOVE;
216
217   if (mystate != STATE_TRACKING)
218     return ABORT_MOVE;
219
220   mystate = STATE_WARPING;
221   sprite->set_action("warping", 1);
222
223   if(hit_script != "") {
224     std::istringstream stream(hit_script);
225     Sector::current()->run_script(stream, "hit-script");
226   } else {
227     GameSession::current()->respawn(target_sector, target_spawnpoint);
228   }
229   sound_manager->play("sounds/warp.wav");
230
231   return CONTINUE;
232 }
233
234 void
235 WillOWisp::goto_node(int node_no)
236 {
237   walker->goto_node(node_no);
238   if(mystate != STATE_PATHMOVING && mystate != STATE_PATHMOVING_TRACK) {
239     mystate = STATE_PATHMOVING;
240   }
241 }
242
243 void
244 WillOWisp::start_moving()
245 {
246   walker->start_moving();
247 }
248
249 void
250 WillOWisp::stop_moving()
251 {
252   walker->stop_moving();
253 }
254
255 void
256 WillOWisp::set_state(const std::string& new_state)
257 {
258   if(new_state == "stopped") {
259     mystate = STATE_STOPPED;
260   } else if(new_state == "idle") {
261     mystate = STATE_IDLE;
262   } else if(new_state == "move_path") {
263     mystate = STATE_PATHMOVING;
264     walker->start_moving();
265   } else if(new_state == "move_path_track") {
266     mystate = STATE_PATHMOVING_TRACK;
267     walker->start_moving();
268   } else if(new_state == "normal") {
269     mystate = STATE_IDLE;
270   } else if(new_state == "vanish") {
271     vanish();
272   } else {
273     std::ostringstream msg;
274     msg << "Can't set unknown willowisp state '" << new_state << "', should "
275       "be stopped, move_path, move_path_track or normal";
276     throw new std::runtime_error(msg.str());
277   }
278 }
279
280 void
281 WillOWisp::expose(HSQUIRRELVM vm, SQInteger table_idx)
282 {
283   if (name.empty())
284     return;
285
286   std::cout << "[DEBUG] Expose me '" << name << "'\n";
287   scripting::WillOWisp* _this = static_cast<scripting::WillOWisp*> (this);
288   expose_object(vm, table_idx, _this, name);
289 }
290   
291 void
292 WillOWisp::unexpose(HSQUIRRELVM vm, SQInteger table_idx)
293 {
294   if (name.empty())
295     return;
296
297   std::cout << "[DEBUG] UnExpose me '" << name << "'\n";
298   scripting::unexpose_object(vm, table_idx, name);
299 }
300
301 /* EOF */