Replaced Ref and RefCounter with std::shared_ptr<>
[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   time_until_explosion(0.0f),
36   is_stunned(false),
37   time_stunned(0.0f),
38   ticking(),
39   grunting()
40 {
41   walk_speed = 80;
42   max_drop_height = 16;
43
44   //Prevent stutter when Tux jumps on Mr Bomb
45   SoundManager::current()->preload("sounds/explosion.wav");
46
47   //Check if we need another sprite
48   if( !reader.get( "sprite", sprite_name ) ){
49     return;
50   }
51   if( sprite_name == "" ){
52     sprite_name = "images/creatures/haywire/haywire.sprite";
53     return;
54   }
55   //Replace sprite
56   sprite = SpriteManager::current()->create( sprite_name );
57 }
58
59 HitResponse
60 Haywire::collision(GameObject& object, const CollisionHit& hit)
61 {
62   return WalkingBadguy::collision(object, hit);
63 }
64
65 HitResponse
66 Haywire::collision_player(Player& player, const CollisionHit& hit)
67 {
68   return WalkingBadguy::collision_player(player, hit);
69 }
70
71 bool
72 Haywire::collision_squished(GameObject& object)
73 {
74   Player* player = dynamic_cast<Player*>(&object);
75   if (player && player->is_invincible()) {
76     player->bounce (*this);
77     kill_fall();
78     return true;
79   }
80
81   if (is_stunned) {
82     if (player)
83       player->bounce (*this);
84     return true;
85   }
86
87   if(WalkingBadguy::is_frozen()) {
88     WalkingBadguy::unfreeze();
89   }
90
91   if (!is_exploding) {
92     set_action ((dir == LEFT) ? "ticking-left" : "ticking-right", /* loops = */ -1);
93     walk_left_action = "ticking-left";
94     walk_right_action = "ticking-right";
95     set_walk_speed (160);
96     time_until_explosion = TIME_EXPLOSION;
97     is_exploding = true;
98
99     ticking = SoundManager::current()->create_sound_source("sounds/fizz.wav");
100     ticking->set_position(get_pos());
101     ticking->set_looping(true);
102     ticking->set_reference_distance(32);
103     ticking->play();
104     grunting = SoundManager::current()->create_sound_source("sounds/grunts.ogg");
105     grunting->set_position(get_pos());
106     grunting->set_looping(true);
107     grunting->set_reference_distance(32);
108     grunting->play();
109   }
110
111   time_stunned = TIME_STUNNED;
112   is_stunned = true;
113   physic.set_velocity_x (0.0);
114   physic.set_acceleration_x (0.0);
115
116   if (player)
117     player->bounce (*this);
118
119   return true;
120 }
121
122 void
123 Haywire::active_update(float elapsed_time)
124 {
125   if (is_exploding) {
126     ticking->set_position(get_pos());
127     grunting->set_position(get_pos());
128     if (elapsed_time >= time_until_explosion) {
129       kill_fall ();
130       return;
131     }
132     else
133       time_until_explosion -= elapsed_time;
134   }
135
136   if (is_stunned) {
137     if (time_stunned > elapsed_time) {
138       time_stunned -= elapsed_time;
139       return;
140     }
141     else { /* if (time_stunned <= elapsed_time) */
142       elapsed_time -= time_stunned;
143       time_stunned = 0.0;
144       is_stunned = false;
145     }
146   }
147
148   if (is_exploding) {
149     Player *p = this->get_nearest_player ();
150     float target_velocity = 0.0;
151
152     if (p) {
153       /* Player is on the right */
154       if (p->get_pos ().x > this->get_pos ().x)
155         target_velocity = walk_speed;
156       else /* player in on the left */
157         target_velocity = (-1.0) * walk_speed;
158     } /* if (player) */
159
160     WalkingBadguy::active_update(elapsed_time, target_velocity);
161   }
162   else {
163     WalkingBadguy::active_update(elapsed_time);
164   }
165 }
166
167 void
168 Haywire::kill_fall()
169 {
170   if(is_exploding) {
171     ticking->stop();
172     grunting->stop();
173   }
174   if(is_valid()) {
175     remove_me();
176     auto explosion = std::make_shared<Explosion>(get_bbox().get_middle());
177     Sector::current()->add_object(explosion);
178   }
179
180   run_dead_script();
181 }
182
183 bool
184 Haywire::is_freezable() const
185 {
186   return true;
187 }
188
189 /* vim: set sw=2 sts=2 et : */
190 /* EOF */