| 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 | |
| 34 | WeakBlock::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 | |
| 60 | HitResponse |
| 61 | WeakBlock::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 | |
| 89 | HitResponse |
| 90 | WeakBlock::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 | |
| 123 | void |
| 124 | WeakBlock::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 | |
| 163 | void |
| 164 | WeakBlock::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 | |
| 175 | void |
| 176 | WeakBlock::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 | |
| 188 | void |
| 189 | WeakBlock::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 | |
| 206 | ObjectSettings |
| 207 | WeakBlock::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 | |