ccede815ccc94ede31891a97080aa9cdf2329b4a
[supertux.git] / src / object / block.cpp
1 #include <config.h>
2
3 #include "block.h"
4 #include "resources.h"
5 #include "player.h"
6 #include "sector.h"
7 #include "special/sprite.h"
8 #include "special/sprite_manager.h"
9 #include "video/drawing_context.h"
10 #include "gameobjs.h"
11 #include "specialriser.h"
12 #include "growup.h"
13 #include "flower.h"
14 #include "oneup.h"
15 #include "star.h"
16 #include "badguy/badguy.h"
17 #include "coin.h"
18
19 static const float BOUNCY_BRICK_MAX_OFFSET=8;
20 static const float BOUNCY_BRICK_SPEED=90;
21 static const float EPSILON = .0001;
22
23 Block::Block(const Vector& pos, Sprite* newsprite)
24   : sprite(newsprite), bouncing(false), bounce_dir(0), bounce_offset(0)
25 {
26   bbox.set_pos(pos);
27   bbox.set_size(32, 32);
28   flags |= FLAG_SOLID;
29   original_y = pos.y;
30 }
31
32 Block::~Block()
33 {
34   delete sprite;
35 }
36
37 HitResponse
38 Block::collision(GameObject& other, const CollisionHit& hitdata)
39 {
40   Player* player = dynamic_cast<Player*> (&other);
41   if(player) {
42     // collided from below?
43     if(hitdata.normal.x == 0 && hitdata.normal.y < 0) {
44       hit(*player);
45     }
46   }
47
48   if(bouncing) {
49     BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
50     if(badguy) {
51       badguy->kill_fall();
52     }
53     Coin* coin = dynamic_cast<Coin*> (&other);
54     if(coin) {
55       coin->collect();
56     }
57   }
58
59   return FORCE_MOVE;
60 }
61
62 void
63 Block::action(float elapsed_time)
64 {
65   if(!bouncing)
66     return;
67   
68   float offset = original_y - get_pos().y;
69   if(offset > BOUNCY_BRICK_MAX_OFFSET) {
70     bounce_dir = BOUNCY_BRICK_SPEED;
71     movement = Vector(0, bounce_dir * elapsed_time);
72   } else if(offset < BOUNCY_BRICK_SPEED * elapsed_time && bounce_dir > 0) {
73     movement = Vector(0, offset);
74     bounce_dir = 0;
75     bouncing = false;
76   } else {
77     movement = Vector(0, bounce_dir * elapsed_time);
78   }
79 }
80
81 void
82 Block::draw(DrawingContext& context)
83 {
84   sprite->draw(context, get_pos(), LAYER_OBJECTS+1);
85 }
86
87 void
88 Block::start_bounce()
89 {
90   bouncing = true;
91   bounce_dir = -BOUNCY_BRICK_SPEED;
92   bounce_offset = 0;
93 }
94
95 //---------------------------------------------------------------------------
96
97 BonusBlock::BonusBlock(const Vector& pos, int newdata)
98   : Block(pos, sprite_manager->create("bonusblock")), data(newdata)
99 {
100   sprite->set_action("default");
101 }
102
103 void
104 BonusBlock::hit(Player& )
105 {
106   try_open();
107 }
108
109 void
110 BonusBlock::try_open()
111 {
112   if(sprite->get_action_name() == "empty") {
113     SoundManager::get()->play_sound(IDToSound(SND_BRICK));
114     return;
115   }
116   
117   Sector* sector = Sector::current();
118   Player& player = *(sector->player);
119   switch(data) {
120     case 1: // coin
121       Sector::current()->add_object(new BouncyCoin(get_pos()));
122       player.get_status().incCoins();
123       break;
124
125     case 2: // grow/fireflower
126       if(player.size == SMALL) {
127         SpecialRiser* riser = new SpecialRiser(
128             new GrowUp(get_pos() + Vector(0, -32)));
129         sector->add_object(riser);
130       } else {
131         SpecialRiser* riser = new SpecialRiser(
132             new Flower(get_pos() + Vector(0, -32), Flower::FIREFLOWER));
133         sector->add_object(riser);
134       }
135       SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
136       break;
137
138     case 5: // grow/iceflower
139       if(player.size == SMALL) {
140         SpecialRiser* riser = new SpecialRiser(
141             new GrowUp(get_pos() + Vector(0, -32)));
142         sector->add_object(riser);                                            
143       } else {
144         SpecialRiser* riser = new SpecialRiser(                               
145             new Flower(get_pos() + Vector(0, -32), Flower::ICEFLOWER));
146         sector->add_object(riser);
147       }      
148       SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
149       break;
150
151     case 3: // star
152       sector->add_object(new Star(get_pos() + Vector(0, -32)));
153       break;
154
155     case 4: // 1up
156       sector->add_object(new OneUp(get_pos()));
157       break;
158
159     default:
160       assert(false);
161   }
162
163   start_bounce();
164   sprite->set_action("empty");
165 }
166
167 //---------------------------------------------------------------------------
168
169 Brick::Brick(const Vector& pos, int data)
170   : Block(pos, sprite_manager->create("brick")), breakable(false),
171     coin_counter(0)
172 {
173   if(data == 1)
174     coin_counter = 5;
175   else
176     breakable = true;
177 }
178
179 void
180 Brick::hit(Player& )
181 {
182   if(sprite->get_action_name() == "empty")
183     return;
184   
185   try_break(true);
186 }
187
188 void
189 Brick::try_break(bool playerhit)
190 {
191   if(sprite->get_action_name() == "empty")
192     return;
193   
194   SoundManager::get()->play_sound(IDToSound(SND_BRICK));
195   Sector* sector = Sector::current();
196   Player& player = *(sector->player);
197   if(coin_counter > 0) {
198     sector->add_object(new BouncyCoin(get_pos()));
199     coin_counter--;
200     player.get_status().incCoins();
201     if(coin_counter == 0)
202       sprite->set_action("empty");
203     start_bounce();
204   } else if(breakable) {
205     if(playerhit && player.size == SMALL) {
206       start_bounce();
207       return;
208     }
209
210     sector->add_object(
211         new BrokenBrick(new Sprite(*sprite), get_pos(), Vector(-100, -400)));
212     sector->add_object(
213         new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(0, 16),
214           Vector(-150, -300)));
215     sector->add_object(
216         new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(16, 0),
217           Vector(100, -400)));
218     sector->add_object(
219         new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(16, 16),
220           Vector(150, -300)));
221     remove_me();
222   }
223 }
224