1 | // SuperTux BadGuy GoldBomb - a bomb that throws up coins when exploding |
2 | // Copyright (C) 2006 Matthias Braun <matze@braunis.de> |
3 | // Copyright (C) 2013 LMH <lmh.0013@gmail.com> |
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/goldbomb.hpp" |
19 | |
20 | #include "audio/sound_manager.hpp" |
21 | #include "audio/sound_source.hpp" |
22 | #include "object/coin_explode.hpp" |
23 | #include "object/explosion.hpp" |
24 | #include "object/player.hpp" |
25 | #include "sprite/sprite.hpp" |
26 | #include "sprite/sprite_manager.hpp" |
27 | #include "supertux/sector.hpp" |
28 | #include "util/reader_mapping.hpp" |
29 | |
30 | GoldBomb::GoldBomb(const ReaderMapping& reader) : |
31 | WalkingBadguy(reader, "images/creatures/gold_bomb/gold_bomb.sprite" , "left" , "right" ), |
32 | tstate(STATE_NORMAL), |
33 | ticking() |
34 | { |
35 | walk_speed = 80; |
36 | max_drop_height = 16; |
37 | |
38 | //Prevent stutter when Tux jumps on Gold Bomb |
39 | SoundManager::current()->preload("sounds/explosion.wav" ); |
40 | |
41 | //Check if we need another sprite |
42 | if ( !reader.get( "sprite" , m_sprite_name ) ){ |
43 | return; |
44 | } |
45 | if (m_sprite_name.empty()) { |
46 | m_sprite_name = "images/creatures/gold_bomb/gold_bomb.sprite" ; |
47 | return; |
48 | } |
49 | //Replace sprite |
50 | m_sprite = SpriteManager::current()->create( m_sprite_name ); |
51 | } |
52 | |
53 | void |
54 | GoldBomb::collision_solid(const CollisionHit& hit) |
55 | { |
56 | if (tstate == STATE_TICKING) { |
57 | if (hit.bottom) { |
58 | m_physic.set_velocity_y(0); |
59 | m_physic.set_velocity_x(0); |
60 | }else if (hit.left || hit.right) |
61 | m_physic.set_velocity_x(-m_physic.get_velocity_x()); |
62 | else if (hit.top) |
63 | m_physic.set_velocity_y(0); |
64 | update_on_ground_flag(hit); |
65 | return; |
66 | } |
67 | WalkingBadguy::collision_solid(hit); |
68 | } |
69 | |
70 | HitResponse |
71 | GoldBomb::collision(GameObject& object, const CollisionHit& hit) |
72 | { |
73 | if (tstate == STATE_TICKING) { |
74 | if ( dynamic_cast<Player*>(&object) ) { |
75 | return ABORT_MOVE; |
76 | } |
77 | if ( dynamic_cast<BadGuy*>(&object) ) { |
78 | return ABORT_MOVE; |
79 | } |
80 | } |
81 | if (is_grabbed()) |
82 | return FORCE_MOVE; |
83 | return WalkingBadguy::collision(object, hit); |
84 | } |
85 | |
86 | HitResponse |
87 | GoldBomb::collision_player(Player& player, const CollisionHit& hit) |
88 | { |
89 | if (tstate == STATE_TICKING) |
90 | return FORCE_MOVE; |
91 | if (is_grabbed()) |
92 | return FORCE_MOVE; |
93 | return WalkingBadguy::collision_player(player, hit); |
94 | } |
95 | |
96 | HitResponse |
97 | GoldBomb::collision_badguy(BadGuy& badguy, const CollisionHit& hit) |
98 | { |
99 | if (tstate == STATE_TICKING) |
100 | return FORCE_MOVE; |
101 | return WalkingBadguy::collision_badguy(badguy, hit); |
102 | } |
103 | |
104 | bool |
105 | GoldBomb::collision_squished(GameObject& object) |
106 | { |
107 | Player* player = dynamic_cast<Player*>(&object); |
108 | if (player && player->is_invincible()) { |
109 | player->bounce(*this); |
110 | kill_fall(); |
111 | return true; |
112 | } |
113 | if (is_valid() && tstate == STATE_NORMAL) { |
114 | tstate = STATE_TICKING; |
115 | m_frozen = false; |
116 | set_action(m_dir == Direction::LEFT ? "ticking-left" : "ticking-right" , 1); |
117 | m_physic.set_velocity_x(0); |
118 | |
119 | if (player) |
120 | player->bounce(*this); |
121 | |
122 | ticking = SoundManager::current()->create_sound_source("sounds/fizz.wav" ); |
123 | ticking->set_position(get_pos()); |
124 | ticking->set_looping(true); |
125 | ticking->set_gain(1.0f); |
126 | ticking->set_reference_distance(32); |
127 | ticking->play(); |
128 | } |
129 | return true; |
130 | } |
131 | |
132 | void |
133 | GoldBomb::active_update(float dt_sec) |
134 | { |
135 | if (tstate == STATE_TICKING) { |
136 | if (on_ground()) m_physic.set_velocity_x(0); |
137 | ticking->set_position(get_pos()); |
138 | if (m_sprite->animation_done()) { |
139 | kill_fall(); |
140 | } |
141 | else if (!is_grabbed()) { |
142 | m_col.m_movement = m_physic.get_movement(dt_sec); |
143 | } |
144 | return; |
145 | } |
146 | if (is_grabbed()) |
147 | return; |
148 | WalkingBadguy::active_update(dt_sec); |
149 | } |
150 | |
151 | void |
152 | GoldBomb::kill_fall() |
153 | { |
154 | if (tstate == STATE_TICKING) |
155 | ticking->stop(); |
156 | |
157 | // Make the player let go before we explode, otherwise the player is holding |
158 | // an invalid object. There's probably a better way to do this than in the |
159 | // GoldBomb class. |
160 | if (is_grabbed()) { |
161 | Player* player = dynamic_cast<Player*>(m_owner); |
162 | |
163 | if (player) |
164 | player->stop_grabbing(); |
165 | } |
166 | |
167 | if (is_valid()) { |
168 | remove_me(); |
169 | Sector::get().add<Explosion>(m_col.m_bbox.get_middle()); |
170 | Sector::get().add<CoinExplode>(get_pos() + Vector (0, -40)); |
171 | } |
172 | |
173 | run_dead_script(); |
174 | } |
175 | |
176 | void |
177 | GoldBomb::ignite() |
178 | { |
179 | kill_fall(); |
180 | } |
181 | |
182 | void |
183 | GoldBomb::grab(MovingObject& object, const Vector& pos, Direction dir_) |
184 | { |
185 | Portable::grab(object,pos,dir_); |
186 | if (tstate == STATE_TICKING){ |
187 | m_col.m_movement = pos - get_pos(); |
188 | m_dir = dir_; |
189 | |
190 | // We actually face the opposite direction of Tux here to make the fuse more |
191 | // visible instead of hiding it behind Tux |
192 | m_sprite->set_action_continued(m_dir == Direction::LEFT ? "ticking-right" : "ticking-left" ); |
193 | set_colgroup_active(COLGROUP_DISABLED); |
194 | } |
195 | else if (m_frozen){ |
196 | m_col.m_movement = pos - get_pos(); |
197 | m_dir = dir_; |
198 | m_sprite->set_action(dir_ == Direction::LEFT ? "iced-left" : "iced-right" ); |
199 | set_colgroup_active(COLGROUP_DISABLED); |
200 | } |
201 | } |
202 | |
203 | void |
204 | GoldBomb::ungrab(MovingObject& object, Direction dir_) |
205 | { |
206 | int toss_velocity_x = 0; |
207 | int toss_velocity_y = 0; |
208 | auto player = dynamic_cast<Player*> (&object); |
209 | |
210 | // toss upwards |
211 | if (dir_ == Direction::UP) |
212 | toss_velocity_y += -500; |
213 | |
214 | // toss to the side when moving sideways |
215 | if (player && player->get_physic().get_velocity_x()*(dir_ == Direction::LEFT ? -1 : 1) > 1) { |
216 | toss_velocity_x += (dir_ == Direction::LEFT) ? -200 : 200; |
217 | toss_velocity_y = (toss_velocity_y < -200) ? toss_velocity_y : -200; |
218 | // toss farther when running |
219 | if (player && player->get_physic().get_velocity_x()*(dir_ == Direction::LEFT ? -1 : 1) > 200) |
220 | toss_velocity_x += static_cast<int>(player->get_physic().get_velocity_x() - (190*(dir_ == Direction::LEFT ? -1 : 1))); |
221 | } |
222 | log_warning << toss_velocity_x << toss_velocity_y << std::endl;//// |
223 | |
224 | //set_pos(object.get_pos() + Vector((dir_ == LEFT ? -33 : 33), get_bbox().get_height()*0.66666 - 32)); |
225 | m_physic.set_velocity(static_cast<float>(toss_velocity_x), |
226 | static_cast<float>(toss_velocity_y)); |
227 | set_colgroup_active(COLGROUP_MOVING); |
228 | Portable::ungrab(object, dir_); |
229 | } |
230 | |
231 | void |
232 | GoldBomb::freeze() |
233 | { |
234 | if (tstate == STATE_NORMAL) { |
235 | WalkingBadguy::freeze(); |
236 | } |
237 | } |
238 | |
239 | bool |
240 | GoldBomb::is_freezable() const |
241 | { |
242 | return true; |
243 | } |
244 | |
245 | bool |
246 | GoldBomb::is_portable() const |
247 | { |
248 | return (m_frozen || (tstate == STATE_TICKING)); |
249 | } |
250 | |
251 | void GoldBomb::stop_looping_sounds() |
252 | { |
253 | if (ticking) { |
254 | ticking->stop(); |
255 | } |
256 | } |
257 | |
258 | void GoldBomb::play_looping_sounds() |
259 | { |
260 | if (tstate == STATE_TICKING && ticking) { |
261 | ticking->play(); |
262 | } |
263 | } |
264 | |
265 | /* EOF */ |
266 | |