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