1// SuperTux - Weak Block
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3// Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
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 "object/weak_block.hpp"
19
20#include <math.h>
21
22#include "audio/sound_manager.hpp"
23#include "badguy/badguy.hpp"
24#include "math/random.hpp"
25#include "object/bullet.hpp"
26#include "object/explosion.hpp"
27#include "supertux/globals.hpp"
28#include "supertux/sector.hpp"
29#include "sprite/sprite.hpp"
30#include "sprite/sprite_manager.hpp"
31#include "util/log.hpp"
32#include "util/reader_mapping.hpp"
33
34WeakBlock::WeakBlock(const ReaderMapping& mapping) :
35 MovingSprite(mapping, "images/objects/weak_block/strawbox.sprite", LAYER_TILES, COLGROUP_STATIC), state(STATE_NORMAL),
36 linked(true),
37 lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite"))
38{
39 m_sprite->set_action("normal");
40 //Check if this weakblock destroys adjacent weakblocks
41 if (mapping.get("linked", linked)){
42 if (! linked){
43 m_default_sprite_name = "images/objects/weak_block/meltbox.sprite";
44 m_sprite_name = m_default_sprite_name;
45 m_sprite = SpriteManager::current()->create(m_sprite_name);
46 m_sprite->set_action("normal");
47 }
48 }
49
50 lightsprite->set_blend(Blend::ADD);
51 lightsprite->set_color(Color(0.3f, 0.2f, 0.1f));
52
53 if (m_sprite_name == "images/objects/weak_block/strawbox.sprite") {
54 SoundManager::current()->preload("sounds/fire.ogg"); // TODO: use own sound?
55 } else if (m_sprite_name == "images/objects/weak_block/meltbox.sprite") {
56 SoundManager::current()->preload("sounds/sizzle.ogg");
57 }
58}
59
60HitResponse
61WeakBlock::collision_bullet(Bullet& bullet, const CollisionHit& hit)
62{
63 switch (state) {
64
65 case STATE_NORMAL:
66 //Ensure only fire destroys weakblock
67 if (bullet.get_type() == FIRE_BONUS) {
68 startBurning();
69 bullet.remove_me();
70 }
71 //Other bullets ricochet
72 else {
73 bullet.ricochet(*this, hit);
74 }
75 break;
76
77 case STATE_BURNING:
78 case STATE_DISINTEGRATING:
79 break;
80
81 default:
82 log_debug << "unhandled state" << std::endl;
83 break;
84 }
85
86 return FORCE_MOVE;
87}
88
89HitResponse
90WeakBlock::collision(GameObject& other, const CollisionHit& hit)
91{
92 switch (state) {
93
94 case STATE_NORMAL:
95 if (auto bullet = dynamic_cast<Bullet*> (&other)) {
96 return collision_bullet(*bullet, hit);
97 }
98 //Explosions destroy weakblocks as well
99 if (dynamic_cast<Explosion*> (&other)) {
100 startBurning();
101 }
102 break;
103
104 case STATE_BURNING:
105 if (m_sprite_name != "images/objects/weak_block/strawbox.sprite")
106 break;
107
108 if (auto badguy = dynamic_cast<BadGuy*> (&other)) {
109 badguy->ignite();
110 }
111 break;
112 case STATE_DISINTEGRATING:
113 break;
114
115 default:
116 log_debug << "unhandled state" << std::endl;
117 break;
118 }
119
120 return FORCE_MOVE;
121}
122
123void
124WeakBlock::update(float )
125{
126 switch (state) {
127
128 case STATE_NORMAL:
129 break;
130
131 case STATE_BURNING:
132 // cause burn light to flicker randomly
133 if (linked) {
134 if (gameRandom.rand(10) >= 7) {
135 lightsprite->set_color(Color(0.2f + gameRandom.randf(20.0f) / 100.0f,
136 0.1f + gameRandom.randf(20.0f)/100.0f,
137 0.1f));
138 } else
139 lightsprite->set_color(Color(0.3f, 0.2f, 0.1f));
140 }
141
142 if (m_sprite->animation_done()) {
143 state = STATE_DISINTEGRATING;
144 m_sprite->set_action("disintegrating", 1);
145 spreadHit();
146 set_group(COLGROUP_DISABLED);
147 lightsprite = SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-tiny.sprite");
148 lightsprite->set_blend(Blend::ADD);
149 lightsprite->set_color(Color(0.3f, 0.2f, 0.1f));
150 }
151 break;
152
153 case STATE_DISINTEGRATING:
154 if (m_sprite->animation_done()) {
155 remove_me();
156 return;
157 }
158 break;
159
160 }
161}
162
163void
164WeakBlock::draw(DrawingContext& context)
165{
166 //Draw the Sprite just in front of other objects
167 m_sprite->draw(context.color(), get_pos(), LAYER_OBJECTS + 10);
168
169 if (linked && (state != STATE_NORMAL))
170 {
171 lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0);
172 }
173}
174
175void
176WeakBlock::startBurning()
177{
178 if (state != STATE_NORMAL) return;
179 state = STATE_BURNING;
180 m_sprite->set_action("burning", 1);
181 if (m_sprite_name == "images/objects/weak_block/meltbox.sprite") {
182 SoundManager::current()->play("sounds/sizzle.ogg");
183 } else if (m_sprite_name == "images/objects/weak_block/strawbox.sprite") {
184 SoundManager::current()->play("sounds/fire.ogg");
185 }
186}
187
188void
189WeakBlock::spreadHit()
190{
191 //Destroy adjacent weakblocks if applicable
192 if (linked) {
193 for (auto& wb : Sector::get().get_objects_by_type<WeakBlock>()) {
194 if (&wb != this && wb.state == STATE_NORMAL)
195 {
196 const float dx = fabsf(wb.get_pos().x - m_col.m_bbox.get_left());
197 const float dy = fabsf(wb.get_pos().y - m_col.m_bbox.get_top());
198 if ((dx <= 32.5f) && (dy <= 32.5f)) {
199 wb.startBurning();
200 }
201 }
202 }
203 }
204}
205
206ObjectSettings
207WeakBlock::get_settings()
208{
209 ObjectSettings result = MovingSprite::get_settings();
210
211 result.add_bool(_("Linked"), &linked, "linked", true);
212
213 result.reorder({"linked", "sprite", "x", "y"});
214
215 return result;
216}
217
218/* EOF */
219