Cleaned up some junk in bonus_block.
[supertux.git] / src / badguy / goldbomb.cpp
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 "audio/sound_manager.hpp"
19 #include "badguy/goldbomb.hpp"
20 #include "object/coin_explode.hpp"
21 #include "object/explosion.hpp"
22 #include "object/player.hpp"
23 #include "object/portable.hpp"
24 #include "sprite/sprite.hpp"
25 #include "sprite/sprite_manager.hpp"
26 #include "supertux/object_factory.hpp"
27 #include "supertux/sector.hpp"
28 #include "util/reader.hpp"
29
30 GoldBomb::GoldBomb(const Reader& reader) :
31   WalkingBadguy(reader, "images/creatures/gold_bomb/gold_bomb.sprite", "left", "right"),
32   tstate(STATE_NORMAL),
33   grabbed(false),
34   grabber(NULL)
35 {
36   walk_speed = 80;
37   max_drop_height = 16;
38
39   //Prevent stutter when Tux jumps on Gold Bomb
40   sound_manager->preload("sounds/explosion.wav");
41
42   //Check if we need another sprite
43   if( !reader.get( "sprite", sprite_name ) ){
44     return;
45   }
46   if( sprite_name == "" ){
47     sprite_name = "images/creatures/gold_bomb/gold_bomb.sprite";
48     return;
49   }
50   //Replace sprite
51   sprite = sprite_manager->create( sprite_name );
52 }
53
54 void
55 GoldBomb::collision_solid(const CollisionHit& hit)
56 {
57   if(tstate == STATE_TICKING) {
58     if(hit.bottom) {
59       physic.set_velocity_y(0);
60       physic.set_velocity_x(0);
61     }else if (hit.left || hit.right)
62       physic.set_velocity_x(-physic.get_velocity_x());
63     else if (hit.top)
64       physic.set_velocity_y(0);
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     return ABORT_MOVE;
75   if(grabbed)
76     return FORCE_MOVE;
77   return WalkingBadguy::collision(object, hit);
78 }
79
80 HitResponse
81 GoldBomb::collision_player(Player& player, const CollisionHit& hit)
82 {
83   if(tstate == STATE_TICKING)
84     return ABORT_MOVE;
85   if(grabbed)
86     return FORCE_MOVE;
87   return WalkingBadguy::collision_player(player, hit);
88 }
89
90 HitResponse
91 GoldBomb::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
92 {
93   if(tstate == STATE_TICKING)
94     return ABORT_MOVE;
95   return WalkingBadguy::collision_badguy(badguy, hit);
96 }
97
98 bool
99 GoldBomb::collision_squished(GameObject& object)
100 {
101   Player* player = dynamic_cast<Player*>(&object);
102   if(player && player->is_invincible()) {
103     player->bounce(*this);
104     kill_fall();
105     return true;
106   }
107   if(is_valid() && tstate == STATE_NORMAL) {
108     tstate = STATE_TICKING;
109     frozen = false;
110     set_action(dir == LEFT ? "ticking-left" : "ticking-right", 1);
111     physic.set_velocity_x(0);
112
113     if (player)
114       player->bounce(*this);
115
116     ticking.reset(sound_manager->create_sound_source("sounds/fizz.wav"));
117     ticking->set_position(get_pos());
118     ticking->set_looping(true);
119     ticking->set_gain(2.0);
120     ticking->set_reference_distance(32);
121     ticking->play();
122   }
123   return true;
124 }
125
126 void
127 GoldBomb::active_update(float elapsed_time)
128 {
129   if(tstate == STATE_TICKING) {
130     ticking->set_position(get_pos());
131     if(sprite->animation_done()) {
132       kill_fall();
133     }
134     else if (!grabbed) {
135       movement = physic.get_movement(elapsed_time);
136     }
137     return;
138   }
139   if(grabbed)
140     return;
141   WalkingBadguy::active_update(elapsed_time);
142 }
143
144 void
145 GoldBomb::kill_fall()
146 {
147   if(tstate == STATE_TICKING)
148     ticking->stop();
149
150   // Make the player let go before we explode, otherwise the player is holding
151   // an invalid object. There's probably a better way to do this than in the
152   // GoldBomb class.
153   if (grabber != NULL) {
154     Player* player = dynamic_cast<Player*>(grabber);
155     
156     if (player)
157       player->stop_grabbing();
158   }
159
160   if(is_valid()) {
161     remove_me();
162     Sector::current()->add_object(new Explosion(get_bbox().get_middle()));
163     Sector::current()->add_object(new CoinExplode(get_pos() + Vector (0, -40)));
164   }
165
166   run_dead_script();
167 }
168
169 void
170 GoldBomb::grab(MovingObject& object, const Vector& pos, Direction dir)
171 {
172   if(tstate == STATE_TICKING){
173     movement = pos - get_pos();
174     this->dir = dir;
175
176     // We actually face the opposite direction of Tux here to make the fuse more
177     // visible instead of hiding it behind Tux
178     sprite->set_action_continued(dir == LEFT ? "ticking-right" : "ticking-left");
179     set_colgroup_active(COLGROUP_DISABLED);
180     grabbed = true;
181     grabber = &object;
182   }
183   else if(frozen){
184     movement = pos - get_pos();
185     this->dir = dir;
186     sprite->set_action(dir == LEFT ? "iced-left" : "iced-right");
187     set_colgroup_active(COLGROUP_DISABLED);
188     grabbed = true;
189   }
190 }
191
192 void
193 GoldBomb::ungrab(MovingObject& object, Direction dir)
194 {
195   int toss_velocity_x = 0;
196   int toss_velocity_y = 0;
197   Player* player = dynamic_cast<Player*> (&object);
198
199   // toss upwards
200   if(dir == UP)
201     toss_velocity_y += -500;
202
203   // toss to the side when moving sideways
204   if(player && player->physic.get_velocity_x()*(dir == LEFT ? -1 : 1) > 1) {
205     toss_velocity_x += (dir == LEFT) ? -200 : 200;
206     toss_velocity_y = (toss_velocity_y < -200) ? toss_velocity_y : -200;
207     // toss farther when running
208     if(player && player->physic.get_velocity_x()*(dir == LEFT ? -1 : 1) > 200)
209       toss_velocity_x += player->physic.get_velocity_x()-(190*(dir == LEFT ? -1 : 1));
210   }
211   log_warning << toss_velocity_x << toss_velocity_y << std::endl;////
212
213   //set_pos(object.get_pos() + Vector((dir == LEFT ? -33 : 33), get_bbox().get_height()*0.66666 - 32));
214   physic.set_velocity(toss_velocity_x, toss_velocity_y);
215   set_colgroup_active(COLGROUP_MOVING);
216   grabbed = false;
217 }
218
219 void
220 GoldBomb::freeze()
221 {
222   if(tstate == STATE_NORMAL){
223     WalkingBadguy::freeze();
224     sprite->set_action(dir == LEFT ? "iced-left" : "iced-right");
225   }
226 }
227
228 bool
229 GoldBomb::is_freezable() const
230 {
231   return true;
232 }
233
234 bool
235 GoldBomb::is_portable() const
236 {
237   return (frozen || (tstate == STATE_TICKING));
238 }
239
240 /* EOF */