1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.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/bomb.hpp"
18
19#include "audio/sound_manager.hpp"
20#include "audio/sound_source.hpp"
21#include "object/explosion.hpp"
22#include "object/player.hpp"
23#include "sprite/sprite.hpp"
24#include "supertux/sector.hpp"
25
26Bomb::Bomb(const Vector& pos, Direction dir_, const std::string& custom_sprite /*= "images/creatures/mr_bomb/mr_bomb.sprite"*/ ) :
27 BadGuy( pos, dir_, custom_sprite ),
28 ticking(SoundManager::current()->create_sound_source("sounds/fizz.wav"))
29{
30 set_action(dir_ == Direction::LEFT ? "ticking-left" : "ticking-right", 1);
31 m_countMe = false;
32
33 ticking->set_position(get_pos());
34 ticking->set_looping(true);
35 ticking->set_gain(1.0f);
36 ticking->set_reference_distance(32);
37 ticking->play();
38}
39
40void
41Bomb::collision_solid(const CollisionHit& hit)
42{
43 if (is_grabbed()) {
44 return;
45 }
46 if (hit.top || hit.bottom)
47 m_physic.set_velocity_y(0);
48 if (hit.left || hit.right)
49 m_physic.set_velocity_x(-m_physic.get_velocity_x());
50 if (hit.crush)
51 m_physic.set_velocity(0, 0);
52
53 update_on_ground_flag(hit);
54}
55
56HitResponse
57Bomb::collision_player(Player& , const CollisionHit& )
58{
59 return ABORT_MOVE;
60}
61
62HitResponse
63Bomb::collision_badguy(BadGuy& , const CollisionHit& )
64{
65 return ABORT_MOVE;
66}
67
68void
69Bomb::active_update(float dt_sec)
70{
71 if (on_ground()) m_physic.set_velocity_x(0);
72
73 ticking->set_position(get_pos());
74 if (m_sprite->animation_done()) {
75 explode();
76 }
77 else if (!is_grabbed()) {
78 m_col.m_movement = m_physic.get_movement(dt_sec);
79 }
80}
81
82void
83Bomb::explode()
84{
85 ticking->stop();
86
87 // Make the player let go before we explode, otherwise the player is holding
88 // an invalid object. There's probably a better way to do this than in the
89 // Bomb class.
90 if (is_grabbed()) {
91 auto player = dynamic_cast<Player*>(m_owner);
92
93 if (player)
94 player->stop_grabbing();
95 }
96
97 if (is_valid()) {
98 remove_me();
99 Sector::get().add<Explosion>(m_col.m_bbox.get_middle());
100 }
101
102 run_dead_script();
103}
104
105void
106Bomb::kill_fall()
107{
108 explode();
109}
110
111void
112Bomb::ignite()
113{
114 explode();
115}
116
117void
118Bomb::grab(MovingObject& object, const Vector& pos, Direction dir_)
119{
120 Portable::grab(object, pos, dir_);
121 m_col.m_movement = pos - get_pos();
122 m_dir = dir_;
123
124 // We actually face the opposite direction of Tux here to make the fuse more
125 // visible instead of hiding it behind Tux
126 m_sprite->set_action_continued(m_dir == Direction::LEFT ? "ticking-right" : "ticking-left");
127 set_colgroup_active(COLGROUP_DISABLED);
128}
129
130void
131Bomb::ungrab(MovingObject& object, Direction dir_)
132{
133 m_dir = dir_;
134 // This object is now thrown.
135 int toss_velocity_x = 0;
136 int toss_velocity_y = 0;
137 auto player = dynamic_cast<Player*> (&object);
138
139 // toss upwards
140 if (dir_ == Direction::UP)
141 toss_velocity_y += -500;
142
143 // toss to the side when moving sideways
144 if (player && player->get_physic().get_velocity_x()*(dir_ == Direction::LEFT ? -1 : 1) > 1) {
145 toss_velocity_x += (dir_ == Direction::LEFT) ? -200 : 200;
146 toss_velocity_y = (toss_velocity_y < -200) ? toss_velocity_y : -200;
147 // toss farther when running
148 if (player && player->get_physic().get_velocity_x()*(dir_ == Direction::LEFT ? -1 : 1) > 200)
149 toss_velocity_x += static_cast<int>(player->get_physic().get_velocity_x() - (190.0f * (dir_ == Direction::LEFT ? -1.0f : 1.0f)));
150 }
151
152 m_physic.set_velocity(static_cast<float>(toss_velocity_x),
153 static_cast<float>(toss_velocity_y));
154
155 set_colgroup_active(COLGROUP_MOVING);
156 Portable::ungrab(object, dir_);
157}
158
159void Bomb::stop_looping_sounds()
160{
161 if (ticking) {
162 ticking->stop();
163 }
164}
165
166void Bomb::play_looping_sounds()
167{
168 if (ticking) {
169 ticking->play();
170 }
171}
172
173/* EOF */
174