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