Icecrusher and Haywire: Use the bounding box to find the nearest player.
[supertux.git] / src / badguy / haywire.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //  Copyright (C) 2010 Florian Forster <supertux at octo.it>
4 //
5 //  This program is free software: you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation, either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 #include "audio/sound_manager.hpp"
19 #include "badguy/bomb.hpp"
20 #include "badguy/haywire.hpp"
21 #include "object/explosion.hpp"
22 #include "object/player.hpp"
23 #include "sprite/sprite.hpp"
24 #include "sprite/sprite_manager.hpp"
25 #include "supertux/object_factory.hpp"
26 #include "supertux/sector.hpp"
27 #include "util/reader.hpp"
28
29 #define TIME_EXPLOSION 5.0
30 #define TIME_STUNNED   0.5
31
32 Haywire::Haywire(const Reader& reader) :
33   WalkingBadguy(reader, "images/creatures/haywire/haywire.sprite", "left", "right"),
34   is_exploding(false),
35   is_stunned(false)
36 {
37   walk_speed = 80;
38   max_drop_height = 16;
39
40   //Prevent stutter when Tux jumps on Mr Bomb
41   sound_manager->preload("sounds/explosion.wav");
42
43   //Check if we need another sprite
44   if( !reader.get( "sprite", sprite_name ) ){
45     return;
46   }
47   if( sprite_name == "" ){
48     sprite_name = "images/creatures/haywire/haywire.sprite";
49     return;
50   }
51   //Replace sprite
52   sprite = sprite_manager->create( sprite_name );
53 }
54
55 /* Haywire created by a dispenser always gets default sprite atm.*/
56 Haywire::Haywire(const Vector& pos, Direction d) :
57   WalkingBadguy(pos, d, "images/creatures/haywire/haywire.sprite", "left", "right"),
58   is_exploding(false),
59   is_stunned(false)
60 {
61   walk_speed = 80;
62   max_drop_height = 16;
63   sound_manager->preload("sounds/explosion.wav");
64 }
65
66 HitResponse
67 Haywire::collision(GameObject& object, const CollisionHit& hit)
68 {
69   return WalkingBadguy::collision(object, hit);
70 }
71
72 HitResponse
73 Haywire::collision_player(Player& player, const CollisionHit& hit)
74 {
75   return WalkingBadguy::collision_player(player, hit);
76 }
77
78 bool
79 Haywire::collision_squished(GameObject& object)
80 {
81   Player* player = dynamic_cast<Player*>(&object);
82   if (player && player->is_invincible()) {
83     player->bounce (*this);
84     kill_fall();
85     return true;
86   }
87
88   if (is_stunned) {
89     player->bounce (*this);
90     return true;
91   }
92
93   if (!is_exploding) {
94     set_action ((dir == LEFT) ? "ticking-left" : "ticking-right", /* loops = */ -1);
95     walk_left_action = "ticking-left";
96     walk_right_action = "ticking-right";
97     set_walk_speed (160);
98     time_until_explosion = TIME_EXPLOSION;
99     is_exploding = true;
100   }
101
102   time_stunned = TIME_STUNNED;
103   is_stunned = true;
104
105   player->bounce (*this);
106   return true;
107 }
108
109 void
110 Haywire::active_update(float elapsed_time)
111 {
112   if (is_exploding) {
113     if (elapsed_time >= time_until_explosion) {
114       kill_fall ();
115       return;
116     }
117     else
118       time_until_explosion -= elapsed_time;
119   }
120
121   if (is_stunned) {
122     if (time_stunned > elapsed_time) {
123       time_stunned -= elapsed_time;
124       return;
125     }
126     else { /* if (time_stunned <= elapsed_time) */
127       elapsed_time -= time_stunned;
128       time_stunned = 0.0;
129       is_stunned = false;
130     }
131   }
132
133   if (is_exploding && !turn_around_timer.started()) {
134     Player *p = Sector::current()->get_nearest_player (this->get_bbox ());
135
136     if (p) {
137       Direction player_dir = LEFT;
138
139       if (p->get_pos ().x > this->get_pos ().x)
140         player_dir = RIGHT;
141
142       if (player_dir != dir)
143         turn_around ();
144     }
145   }
146
147   WalkingBadguy::active_update(elapsed_time);
148 }
149
150 void
151 Haywire::kill_fall()
152 {
153   if(is_valid()) {
154     remove_me();
155     Explosion* explosion = new Explosion(get_bbox().get_middle());
156     Sector::current()->add_object(explosion);
157   }
158
159   run_dead_script();
160 }
161
162 void
163 Haywire::freeze()
164 {
165   WalkingBadguy::freeze();
166   sprite->set_action(dir == LEFT ? "iced-left" : "iced-right");
167 }
168
169 bool
170 Haywire::is_freezable() const
171 {
172   return true;
173 }
174
175 /* vim: set sw=2 sts=2 et : */
176 /* EOF */