1// SuperTux
2// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "object/brick.hpp"
18
19#include "audio/sound_manager.hpp"
20#include "badguy/badguy.hpp"
21#include "object/bouncy_coin.hpp"
22#include "object/explosion.hpp"
23#include "object/icecrusher.hpp"
24#include "object/player.hpp"
25#include "object/portable.hpp"
26#include "sprite/sprite.hpp"
27#include "sprite/sprite_manager.hpp"
28#include "supertux/constants.hpp"
29#include "supertux/sector.hpp"
30#include "util/reader_mapping.hpp"
31
32Brick::Brick(const Vector& pos, int data, const std::string& spriteName) :
33 Block(SpriteManager::current()->create(spriteName)),
34 m_breakable(false),
35 m_coin_counter(0)
36{
37 m_col.m_bbox.set_pos(pos);
38 if (data == 1) {
39 m_coin_counter = 5;
40 } else {
41 m_breakable = true;
42 }
43}
44
45Brick::Brick(const ReaderMapping& mapping) :
46 Block(mapping, "images/objects/bonus_block/brick.sprite"),
47 m_breakable(),
48 m_coin_counter(0)
49{
50 mapping.get("breakable", m_breakable, true);
51 if (!m_breakable) {
52 m_coin_counter = 5;
53 }
54}
55
56void
57Brick::hit(Player& player)
58{
59 if (m_sprite->get_action() == "empty")
60 return;
61
62 try_break(&player);
63}
64
65HitResponse
66Brick::collision(GameObject& other, const CollisionHit& hit_)
67{
68 auto player = dynamic_cast<Player*> (&other);
69 if (player) {
70 if (player->m_does_buttjump) try_break(player);
71 if (player->is_stone() && player->get_velocity().y >= 280) try_break(player); // stoneform breaks through bricks
72 }
73
74 auto badguy = dynamic_cast<BadGuy*> (&other);
75 if (badguy) {
76 // hit contains no information for collisions with blocks.
77 // Badguy's bottom has to be below the top of the brick
78 // SHIFT_DELTA is required to slide over one tile gaps.
79 if ( badguy->can_break() && ( badguy->get_bbox().get_bottom() > m_col.m_bbox.get_top() + SHIFT_DELTA ) ) {
80 try_break(player);
81 }
82 }
83 auto portable = dynamic_cast<Portable*> (&other);
84 if (portable) {
85 auto moving = dynamic_cast<MovingObject*> (&other);
86 if (moving->get_bbox().get_top() > m_col.m_bbox.get_bottom() - SHIFT_DELTA) {
87 try_break(player);
88 }
89 }
90 auto explosion = dynamic_cast<Explosion*> (&other);
91 if (explosion && explosion->hurts()) {
92 try_break(player);
93 }
94 auto icecrusher = dynamic_cast<IceCrusher*> (&other);
95 if (icecrusher && m_coin_counter == 0)
96 try_break(player);
97 return Block::collision(other, hit_);
98}
99
100void
101Brick::try_break(Player* player)
102{
103 if (m_sprite->get_action() == "empty")
104 return;
105
106 SoundManager::current()->play("sounds/brick.wav");
107 Player& player_one = Sector::get().get_player();
108 if (m_coin_counter > 0 ) {
109 Sector::get().add<BouncyCoin>(get_pos(), true);
110 m_coin_counter--;
111 player_one.get_status().add_coins(1);
112 if (m_coin_counter == 0)
113 m_sprite->set_action("empty");
114 start_bounce(player);
115 } else if (m_breakable) {
116 if (player) {
117 if (player->is_big()) {
118 start_break(player);
119 return;
120 } else {
121 start_bounce(player);
122 return;
123 }
124 }
125 break_me();
126 }
127}
128
129ObjectSettings
130Brick::get_settings()
131{
132 ObjectSettings result = Block::get_settings();
133 result.add_bool(_("Breakable"), &m_breakable, "breakable");
134 return result;
135}
136
137/* EOF */
138