1 // SuperTux - "Will-O-Wisp" Badguy
2 // Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
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.
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.
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/>.
17 #include "badguy/willowisp.hpp"
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"
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";
37 WillOWisp::WillOWisp(const Reader& reader) :
38 BadGuy(reader, "images/creatures/willowisp/willowisp.sprite", LAYER_FLOATINGOBJECTS),
40 target_sector("main"),
41 target_spawnpoint("main"),
49 lightsprite(sprite_manager->create("images/objects/lightmap_light/lightmap_light-small.sprite"))
53 track_range = TRACK_RANGE;
54 vanish_range = VANISH_RANGE;
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);
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));
71 mystate = STATE_PATHMOVING_TRACK;
75 sound_manager->preload(SOUNDFILE);
76 sound_manager->preload("sounds/warp.wav");
78 lightsprite->set_blend(Blend(GL_SRC_ALPHA, GL_ONE));
79 lightsprite->set_color(Color(0.0f, 0.2f, 0.0f));
81 sprite->set_action("idle");
85 WillOWisp::draw(DrawingContext& context)
87 sprite->draw(context, get_pos(), layer);
89 context.push_target();
90 context.set_target(DrawingContext::LIGHTMAP);
92 sprite->draw(context, get_pos(), layer);
93 lightsprite->draw(context, get_bbox().get_middle(), 0);
99 WillOWisp::active_update(float elapsed_time)
101 Player* player = get_nearest_player();
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);
112 if (dist.norm() <= track_range) {
113 mystate = STATE_TRACKING;
118 if (dist.norm() > vanish_range) {
120 } else if (dist.norm() >= 1) {
121 Vector dir = dist.unit();
122 movement = dir * elapsed_time * flyspeed;
124 /* We somehow landed right on top of the player without colliding.
125 * Sit tight and avoid a division by zero. */
127 sound_source->set_position(get_pos());
131 if(sprite->animation_done()) {
135 case STATE_VANISHING: {
136 Vector dir = dist.unit();
137 movement = dir * elapsed_time * flyspeed;
138 if(sprite->animation_done()) {
144 case STATE_PATHMOVING:
145 case STATE_PATHMOVING_TRACK:
146 if(walker.get() == NULL)
148 movement = walker->advance(elapsed_time) - get_pos();
149 if(mystate == STATE_PATHMOVING_TRACK && dist.norm() <= track_range) {
150 mystate = STATE_TRACKING;
160 WillOWisp::activate()
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();
171 WillOWisp::deactivate()
173 sound_source.reset(NULL);
178 case STATE_PATHMOVING:
179 case STATE_PATHMOVING_TRACK:
182 mystate = STATE_IDLE;
185 case STATE_VANISHING:
194 mystate = STATE_VANISHING;
195 sprite->set_action("vanishing", 1);
196 set_colgroup_active(COLGROUP_DISABLED);
200 WillOWisp::collides(GameObject& other, const CollisionHit& ) {
201 Lantern* lantern = dynamic_cast<Lantern*>(&other);
203 if (lantern && lantern->is_open())
206 if (dynamic_cast<Player*>(&other))
213 WillOWisp::collision_player(Player& player, const CollisionHit& ) {
214 if(player.is_invincible())
217 if (mystate != STATE_TRACKING)
220 mystate = STATE_WARPING;
221 sprite->set_action("warping", 1);
223 if(hit_script != "") {
224 std::istringstream stream(hit_script);
225 Sector::current()->run_script(stream, "hit-script");
227 GameSession::current()->respawn(target_sector, target_spawnpoint);
229 sound_manager->play("sounds/warp.wav");
235 WillOWisp::goto_node(int node_no)
237 walker->goto_node(node_no);
238 if(mystate != STATE_PATHMOVING && mystate != STATE_PATHMOVING_TRACK) {
239 mystate = STATE_PATHMOVING;
244 WillOWisp::start_moving()
246 walker->start_moving();
250 WillOWisp::stop_moving()
252 walker->stop_moving();
256 WillOWisp::set_state(const std::string& new_state)
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") {
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());
281 WillOWisp::expose(HSQUIRRELVM vm, SQInteger table_idx)
286 std::cout << "Expose me '" << name << "'\n";
287 scripting::WillOWisp* _this = static_cast<scripting::WillOWisp*> (this);
288 expose_object(vm, table_idx, _this, name);
292 WillOWisp::unexpose(HSQUIRRELVM vm, SQInteger table_idx)
297 std::cout << "UnExpose me '" << name << "'\n";
298 scripting::unexpose_object(vm, table_idx, name);