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 "badguy/haywire.hpp"
19
20#include "audio/sound_manager.hpp"
21#include "audio/sound_source.hpp"
22#include "object/explosion.hpp"
23#include "object/player.hpp"
24#include "sprite/sprite_manager.hpp"
25#include "supertux/sector.hpp"
26#include "util/reader_mapping.hpp"
27
28namespace {
29
30const float TIME_EXPLOSION = 5.0f;
31const float TIME_STUNNED = 0.5f;
32
33const float NORMAL_WALK_SPEED = 80.0f;
34const float EXPLODING_WALK_SPEED = 160.0f;
35
36} // namespace
37
38Haywire::Haywire(const ReaderMapping& reader) :
39 WalkingBadguy(reader, "images/creatures/haywire/haywire.sprite", "left", "right"),
40 is_exploding(false),
41 time_until_explosion(0.0f),
42 is_stunned(false),
43 time_stunned(0.0f),
44 ticking(),
45 grunting()
46{
47 walk_speed = NORMAL_WALK_SPEED;
48 max_drop_height = 16;
49
50 //Prevent stutter when Tux jumps on Mr Bomb
51 SoundManager::current()->preload("sounds/explosion.wav");
52
53 //Check if we need another sprite
54 if ( !reader.get( "sprite", m_sprite_name ) ){
55 return;
56 }
57 if (m_sprite_name.empty()) {
58 m_sprite_name = "images/creatures/haywire/haywire.sprite";
59 return;
60 }
61 //Replace sprite
62 m_sprite = SpriteManager::current()->create( m_sprite_name );
63}
64
65bool
66Haywire::collision_squished(GameObject& object)
67{
68 auto player = dynamic_cast<Player*>(&object);
69 if (player && player->is_invincible()) {
70 player->bounce (*this);
71 kill_fall();
72 return true;
73 }
74
75 if (is_stunned) {
76 if (player)
77 player->bounce (*this);
78 return true;
79 }
80
81 if (WalkingBadguy::is_frozen()) {
82 WalkingBadguy::unfreeze();
83 }
84
85 if (!is_exploding) {
86 start_exploding();
87 }
88
89 time_stunned = TIME_STUNNED;
90 is_stunned = true;
91 m_physic.set_velocity_x(0.f);
92 m_physic.set_acceleration_x(0.f);
93
94 if (player)
95 player->bounce (*this);
96
97 return true;
98}
99
100void
101Haywire::active_update(float dt_sec)
102{
103 if (is_exploding) {
104 ticking->set_position(get_pos());
105 grunting->set_position(get_pos());
106 if (dt_sec >= time_until_explosion) {
107 kill_fall ();
108 return;
109 }
110 else
111 time_until_explosion -= dt_sec;
112 }
113
114 if (is_stunned) {
115 if (time_stunned > dt_sec) {
116 time_stunned -= dt_sec;
117 }
118 else { /* if (time_stunned <= dt_sec) */
119 time_stunned = 0.f;
120 is_stunned = false;
121 }
122 }
123
124 if (is_exploding) {
125 auto p = get_nearest_player ();
126 float target_velocity = 0.f;
127
128 if (p && time_stunned == 0.f) {
129 /* Player is on the right */
130 if (p->get_pos ().x > get_pos ().x)
131 target_velocity = walk_speed;
132 else /* player in on the left */
133 target_velocity = (-1.f) * walk_speed;
134 }
135
136 WalkingBadguy::active_update(dt_sec, target_velocity);
137 }
138 else {
139 WalkingBadguy::active_update(dt_sec);
140 }
141}
142
143void
144Haywire::kill_fall()
145{
146 if (is_exploding) {
147 ticking->stop();
148 grunting->stop();
149 }
150 if (is_valid()) {
151 remove_me();
152 Sector::get().add<Explosion>(m_col.m_bbox.get_middle());
153 }
154
155 run_dead_script();
156}
157
158bool
159Haywire::is_freezable() const
160{
161 return true;
162}
163
164void
165Haywire::ignite()
166{
167 kill_fall();
168}
169
170void
171Haywire::freeze() {
172 BadGuy::freeze();
173 if (is_exploding) {
174 stop_exploding();
175 }
176}
177
178void
179Haywire::start_exploding()
180{
181 set_action ((m_dir == Direction::LEFT) ? "ticking-left" : "ticking-right", /* loops = */ -1);
182 walk_left_action = "ticking-left";
183 walk_right_action = "ticking-right";
184 set_walk_speed (EXPLODING_WALK_SPEED);
185 time_until_explosion = TIME_EXPLOSION;
186 is_exploding = true;
187
188 ticking = SoundManager::current()->create_sound_source("sounds/fizz.wav");
189 ticking->set_position(get_pos());
190 ticking->set_looping(true);
191 ticking->set_reference_distance(32);
192 ticking->play();
193 grunting = SoundManager::current()->create_sound_source("sounds/grunts.ogg");
194 grunting->set_position(get_pos());
195 grunting->set_looping(true);
196 grunting->set_reference_distance(32);
197 grunting->play();
198}
199
200void
201Haywire::stop_exploding()
202{
203 walk_left_action = "left";
204 walk_right_action = "right";
205 set_walk_speed(NORMAL_WALK_SPEED);
206 time_until_explosion = 0.0f;
207 is_exploding = false;
208
209 if (ticking)
210 ticking->stop();
211
212 if (grunting)
213 grunting->stop();
214}
215
216void Haywire::stop_looping_sounds()
217{
218 if (ticking) {
219 ticking->stop();
220 }
221 if (grunting) {
222 grunting->stop();
223 }
224}
225
226void Haywire::play_looping_sounds()
227{
228 if (is_exploding) {
229 if (ticking) {
230 ticking->play();
231 }
232 if (grunting) {
233 grunting->play();
234 }
235 }
236}
237
238/* EOF */
239